How updating all your packages at once is a good idea?

Couldn’t you do this and just have those packages on unstable to test newer versions

stable = import inputs.nixpkgs { inherit system; };
unstable = import inputs.nixpkgs-unstable { inherit system; };

environment.systemPackages = with stable; [
  git
  firefox

  unstable.neovim
  unstable.ripgrep
  unstable.fd
  unstable.bat
];

I never implied such thing. Why do you think that? It’s because it is not possible to have caches of certain packages that my “specific required versions” requires? Or why?

Yes, both true. Most CLIs take very little to build, but some are rust based, and those take longer (for example herdr).

Can you give me some more detils on this?

I look at devenv a long time ago. But here I’m looking for a solution for my system. In individual projects I’m usually not that worried about what version I’m getting (99% of the time)

That is interesting. I’ll have a look at it

Yes, but that gives you two versions, and that is what I usually do. In fact, I think I use unstable by default. The problem is that sometimes I want to update a new package version without having to update everything else, just that one package. So I either have to move all my other packages to stable, and then update unstable just to test a new package. And in many cases, the packages that I’m using are not in the right version in stable. Am I making sense?

I have no idea if this override makes sense anymore, but at some point I needed a gitlab binary that was a later version than on stable. Couple of hash changes and I get whatever version I want (within reason).

~/.config/home-manager master *4 +8 !1 ?3                                          19:55:24
❯ cat -p src/glab.nix
{
  config,
  lib,
  pkgs,
  ...
}:
let
  glab =
    let
      version = "1.88.0";
    in
    pkgs.glab.overrideAttrs (prev: {
      inherit version;
      src = prev.src.override {
        tag = "v${version}";
        hash = "sha256-ZIHkS9WIdZmmM14Y8GgcN5qbupD8ePN5LofQaZJYW7M=";
      };
      vendorHash = "sha256-2zIox8u8g0tF6i29+AwP41/IRgWtIaZLAUgchUTl+ds=";
    });
in
{
  config = lib.mkMerge [
    {
      home.packages = [ glab ];
    }
    (lib.mkIf config.programs.git.enable {
      programs.git.settings.credential."https://gitlab.com".helper =
        "!${lib.getExe glab} auth git-credential";
    })
  ];
}

There is a chapter in the manual: Nixpkgs Reference Manual

Mate it doesnt make sense

You should be using stable as a defsult then unstable on what you really need newer versions.

So then when you update only those that are specified as unstable will get the latest updates while leaving your stable system as is

1 Like

I based my statement on the following:

Based on your writing, I had inferred that you were aware of how to override the nixpkgs source for a package or mix multiple instances of nixpkgs. Perhaps I was wrong?

If I was, look into https://wiki.nixos.org/wiki/Overlays which shows a few different ways of managing exceptions for specific packages. You can either just update the “recipe”/derivation for the specific package, or you can pull in a full derivation from a cached build of nixpkgs.

Note that overlaying produces a coherent package set. In other words, if you replace a dependency in an overlay, it changes the definition of all packages that depend on it as well.

Rather than truly overlaying the packages, you can also just add the override/overrideAttrs definition to your environment.systemPackages

1 Like

No, you were not wrong. My wording was not explicit about what part was tedious. Indeed having to wait for things to compile is not the greatest thing ever, but it’s something I can deal with. What I find “cumbersome” is to have to deal with so many entry points, but specially finding the right nixpkgs commit hash that contains the app version that I want to use. All that manual work is what I consider tedious. Compiling, once it is cached, is not that much of a problem.

That said, I’m not an expert on nix. I’m more a user that started using the most basic features of flakes for dev environments, loved it, and tried to extend to everything else.

This is where I showcase how newie I am. I am still digesting the meaning of overlays, I read several definitions of it and it is still unclear. What should I add to my override attrs?

Yeah, I get that. But if I have 20 packages in unstable, and I’m happy with the version of 19 of them, that will force me to update 20 to just get the latest version of 1. Then, I will have to read the changelog of 20 packages instead of 1. Am I making more sense now?

1 Like

Reproducibility, declarativity, and cherry-picking of updates is a difficult combination of traits to actually keep, because of dependencies. Nix is structured so that if anything in the transitive dependency closure of a package is different, the package is considered different, and must be built and cached separately. Nixpkgs is structured so that a reasonable amount of building can be done and have normal usage always be cached. This means that the exact commit of nixpkgs you build from determines not just what versions of leaf packages you get, but also all the versions in the entire closure all the way back to things like glibc. You cannot keep an old version of a package while updating its dependencies and still have caching. You can keep the old version of the package and its old dependencies (at the cost of more space), but in practice the only ways to do this would be to keep multiple entire copies of nixpkgs involved in your declarative code, and that gets to be pretty unwieldy if you do too much of it, or to give up declarativity as nix profile does.

6 Likes

I was wondering about the same exact thing lately, because I needed to update a single package with my own changes recently merged to master. Bringing an entire extra copy of nixpkgs to my flake inputs felt like the biggest waste.

It seems that independent package updates would require changing the model of how they’re stored (or wrapping the existing model somehow). I can imagine that individual package would have to have their own lockfiles, for starters

I’ve also asked myself whether I wanted to have everything tied to a single nixpkgs commit but when trying to find an alternative way I sometimes found more problems than solutions.
It came down to the question of grouping what must be updated together, which is usually non-trivial and involves tradeoffs about consistency and security.

1 Like

Take the terminal alacritty as example:

Normally people install it with

{
  environment.systemPackages = [ pkgs.alacritty ];
}

But looking at the code, you can see there are two variants in the package, that depends on the variable withGraphics that can be set here and it is false by default.

In this case, To set withGraphics to true, use override:

{
  environment.systemPackages = [
    (pkgs.alacritty.override { withGraphics = true; })
  ];
}

If you don’t what those two predefined src and cargoHash, you can directly override them with overrideAttrs:

{
  environment.systemPackages = [
    (pkgs.alacritty.overrideAttrs {
      src = .....;
      version = ......;
      cargoHash = .... ;
    })
  ];
}

But actually, Rust packages are special and the above does not work and need extra steps, but you get the idea of override and overrideAttrs.

For both:

{
  environment.systemPackages = [
    ((pkgs.alacritty.overrideAttrs {
      src = .....;
      version = ......;
      cargoHash = .... ;
    }).override { some_other_variable = something; })
  ];
}

For overlays, it is just the same, but it is applied system wide. That means all the package depending on alacritty now also depend on your custom one, which may also trigger rebuild.

overlays syntax for NixOS is just like this for above withGraphics = true

{
  nixpkgs.overlays = [
    (final: prev: {
      alacritty = prev.alacritty.override { withGraphics = true; };
    })
  ];
}
1 Like

Yes, indeed. The former is what I like about Nix, but when it’s time to update some package, I forget all that and I just think in the convenience of the latter

Yes, true. And that could take huge amounts of space.

Then multiply it by several packages that you want different versions of packages

That is what motivated me to open this thread to begin with

Ok, thanks. Very great explanation!

Ah, my bad, i didn’t realize you were on Mac. Yeah what you want could theoretically be done in multiple ways, like for example giving every single package its own flake input, but like you describe, that becomes a true pain. Nixpkgs is pretty much a monolith as others described it, so it’s tricky to deal with this.

1 Like

It wont force you to update 19 of them right.

If you plan ahead and you pin 19 of them in your flake then it will update just the one.

But i get your point in that maybe pinning should instead have an opposite alternative like marking this specifc time around to only update this one. Like mark x package to update then anything unmarked is implied not scheduled to be upgraded.

Or does this already exist?

I do something similar to this: Nix Overrides That Expire Themselves (not my article)

3 Likes

I haven’t seen it mentioned before but whenever I require a specific version of something I go to this Lazamar website where I get copy paste friendly instructions on several ways to get them.

Eg to select any known version of lilypond I used this search:

5 Likes

Why do you need to use old versions of apps? You won’t be getting any security updates if you do! You probably shouldn’t be using lazamar and pin specific nixpkgs commit, unless it’s necessary. And even then, it should be only temporary.

You very much should update regularly. All packages, not just some selected ones.

Nixpkgs provides only versions that are supported by upstream. E.g. with python, we have python311 up to python315 in nixpkgs. If there’s a version of package supported by upstream that you need, but it’s not in nixpkgs, you should package it yourself. In which case override might be an easiest approach. You can even consider PR-ing this other version to nixpkgs.

1 Like

This to me sounds like you’ve made a fundamental error in maintaining software in assuming that software exists within a vacuum irrespective of the software that existed within that same time and context. In other words, you’ve made your own problem by assuming that you should be updating just one package at a time. And in the event that you did need to reference a particular package at a given version nix does provide you the tools to do so, but often that’s the bandaid that must developers use for not keeping up on managing external dependencies.

2 Likes

That is new to me. You can pin specific packages in the lock somehow? And then when updating nixpkgs they don’t update? Or how does that work?

You are both are mentioning that like I was some kind of lazy person that dones’t want to do it’s homework.

Maybe you are in the time of your life where you can spend an weekend fixing your system because updates, but I’m not in that part of my life anymore. I don’t even have an evening to dedicate to fix my VIM because latest packages updates or my system for the same reason.

I need stable working versions of my tools so I can do my work and then spend time with my family.
Still, from time to time, I want to try the latest version of some tool that is going to deliver interesting stuff to my workflow without having to check another 50 potentially breaking updates.