Why are overlays better than pkgOverrides?

I’m trying to understand - it seems to me that overlays are pretty similar to packageOverrides, and in fact the Wiki proposes using the latter: https://nixos.wiki/wiki/Overlays#Python_Packages_Overlay

Are they functionally the same?

I’m also wondering why they can’t be used for adding/adjusting NixOS services (afaict). When I heard the name overlay I was excited, hoping that meant being able to tweak nixpkgs services without having to have the entire tree checked out, but it seems that’s not how it works?

2 Likes

Well, I am now testing an overlay for Wayland. The funny thing is I can graft a custom package tree without modifying the main nixpkgs tree. I don’t need to add files to the original tree, I can just create a new, clean directory containing all my stuff and work on it without interfering the original tree.

That’s what I do too:

.config/nixpkgs/config.nix:

{ pkgs }:
{
        packageOverrides = pkgs: rec {
                ccacheWrapper = pkgs.ccacheWrapper.override {
                        extraConfig = ''
                                export CCACHE_COMPRESS=1 CCACHE_DIR=/nix/var/ccache CCACHE_UMASK=002
                        '';
                };
                z = pkgs.callPackage ./z.nix {};
        };
}

In this I use different attributes for ccacheWrapper and I add z.

Overlays compose with many overlays, packageOverrides can only be set once, and don’t compose with many packageOverrrides.

3 Likes

packageOverrides are in fact currently implemented as a built-in overlay. The overlay used for packageOverrides sits directly beneath the ones implemented as custom overlays.

As stated before, packageOverrides don’t compose well. The main problem is the only argument it has is the super set, i.e. the set of packages immediately prior to packageOverrides (and later overlays) being applied. This means that any packages subsequently modified by other overrides are not accessible to packageOverrides even though they are accessible to other overlays via the self parameter. callPackage itself will still use the self package set for resolving dependencies, so your z.nix there will have any dependencies provided by overlays if applicable, but any direct references to packages from the pkgs set won’t take overlays into account.

Overlays are also just easier to work with. Drop a new file or dir into ~/.config/nixpkgs/overlays (or <nixpkgs-overlays> if defined in NIX_PATH) and you have yourself an overlay. You can easily add and remove overlays without editing any individual file. You can distribute overlays as git repos that get checked out into this directory, or have install scripts that symlink overlays into this directory (such as rust-overlay-install.sh). You can import nixpkgs with a custom set of overlays (I do this in a maintenance script for my custom overlays, it takes each existing overlay and wraps it in a function that records all of the overlay packages, in order to search just those packages for update scripts).

13 Likes

Great explanation, thanks! That makes a lot of sense.

I wonder, would it be possible to write top-level/all-packages.nix as a set of overlays, so that the pieces are smaller and GitHub can handle them better?

I also wonder if it would be possible to use the same system for the nixos modules?

top-level/all-packages.nix is in fact already evaluated as an overlay with a two extra parameters (which is to say, it’s wrapped in an overlay that provides those two parameters).

Instead of splitting it into a set of overlays, we could just have the overlay import a series of files and merge the contents (using a function that complains if it’s going to overwrite a key). I don’t know if there are any performance implications to this though.

I’m not sure what you’re envisioning here. Modules are merged using custom logic, rather than overlaying each other.

I would like to add custom modules to NixOS without having to fork nixpkgs, much in the same way you can add an overlay to add packages.

Just use imports in your /etc/nixos/configuration.nix. Each imported file is in fact a module.

4 Likes

:man_facepalming:
Thanks! I never considered the possibility, d’oh. That’s good news :slight_smile:

1 Like

I wondered this myself and I eventually tracked down the source of my cognitive dissonance:

  • A static set of overlays can be squashed into an override, and in fact this has better syntactic locality and denotationality. Therefore my personal NixOS configuration only uses overrides.
  • However, if you’re mixing and matching (an overlay for Mac users, an overlay for DVORAK users…) then overlays make sense. You no longer need denotationality since the overlay is configuration-specific and the installer can indeed overlay the installation with their custom set of overlays.
1 Like

Note also https://github.com/NixOS/nixpkgs/pull/43560 where I proposed deprecating packageOverrides (will follow it up with an RFC eventually). One of the major disadvantages of packageOverrides is that it’s yet another thing named “override”, which is unnecessarily confusing for beginners.

5 Likes