This is a persistent nuisance when using NixOS (and Nix in general): if you want packages that aren’t outdated, you have to use nixos-unstable. But looking at the newly broken jobs of any evaluation of nixos/unstable in Hydra, there are always at least a couple packages that end up getting broken at random. As the size of your configuration grows, so does the probability that the next version of nixpkgs will break one of the packages you use, and prevent you from updating at that time.
I, as the user, don’t know about this until the build blows up in my face when I update. There’s no caching for failed builds as well, so whenever new starts to compile, I know it’s almost certainly going to fail. I’ve had it succeed as well on some occasions, but that’s was probably due to transient network failures or something along those lines preventing Nix from pulling those builds from the cache.
People work around this by skipping that update entirely, manually excluding the broken packages from their configuration until they’re fixed, or by splicing together multiple nixpkgs versions. I’ll ignore the first two workarounds since this is clearly not some insurmountable problem, and I believe all the pieces are there to (mostly) fix it, but they haven’t been put together yet.
Nixpkgs is a monorepo, and the packages are guaranteed to be updated and tested in lockstep with each other. This is a very strong constraint, and is not necessary for the vast majority of applications. Barring major ecosystem or ABI breakages, you can run applications from one version of nixpkgs on a system built from another version, alongside applications from a third version and so on. Unfortunately, when version constraints between packages do exist, there is no guarantee that they will be specified, since there is an underlying assumption that they will all be updated in lockstep anyway.
If certain packages were held back from updating when they break, there is a small probability that it could result in a system configuration that breaks at runtime rather than build time. I think that (and I’m talking entirely out of my ass at this point, I don’t have any concrete data) this is an acceptable risk and that users should get the option to do it anyway. It could never result in a fully working system becoming broken (because no packages would be held back in that case), but it could temporarily break components based on the affected packages. And runtime breakages happen already, however rare they are. Fortunately, NixOS makes it possible to write VM tests, and I assume that anyone who would be bothered by this new (optional) potential breakage would already have some smoke tests set up before they deploy new versions. One way to mitigate this would be to have two nixpkgs instances: one for important system services (so you’re not left with a bootable, but completely broken system), and one for applications where you accept the possibility of finding out something’s broken after you deploy the update rather than before. Again, assuming you don’t already have tests for this.
As for how this would be implemented, as I wrote before, all the pieces are there already. You would need a new flake that proxies legacyPackages.${system} from multiple versions of nixpkgs depending on the package (and yes, there would definitely be ways for users to do weird things and dig up the broken versions underneat, but why would you do that). You could also use a primary nixpkgs version and create an overlay that replaces broken packages with versions from secondary versions.
You would need a list of broken packages as well as the latest nixpkgs version where they build successfully. Hydra already has all this information, although I’m not familiar with the API, so I don’t know if there’s an efficient way to retrieve it.
As for how this could be done with 3rd party flakes, I have no idea. Pray they tag their releases nicely?