Solvednixpkgs NixOS services: When to have a package option

Issue description

It has become somewhat of a pattern to add a package option to NixOS service modules for selecting a package to use for the service. Doing a quick count, of the ~600 service modules in nixpkgs about 120 of them have a package option. For comparison, the total amount of options in nixpkgs is about 7000. Every new NixOS option increases evaluation time for all NixOS system evaluations, whether you use it or not. Adding an option just because other services do it doesn't sound sensible. I'd rather add this option only once a need for it arises.

This is an issue to track opinions about this.

Alternative

In general, all packages can already be overridden via overlays. To override the package foo with foo2:

{
  nixpkgs.overlays = [(self: super: {
    foo = self.foo2;
  })];
}

The need for such an option

The 3 uses I see for a package option are:

  • There are alternate packages you would want to use and being able to use different packages is an integral part of the module. Having an option makes this possibility discoverable. postgresql is such an example (postgresql_9_3, ..., postgresql_11).
  • Using an overlay for it would require a lot of rebuilds, because overlays not only change the package the service uses, but all the other parts of the system as well. curl would be such an example.
  • Using an overlay for it would change some other part of the system you don't want to change. E.g. 2 services that need the same package but different versions of it. An overlay couldn't change just one of them.

Related

For reference, I used this to find these:

while true; do firefox $(git blame $(fzf) | rg '([^ ]+) .*package = mkOption' -or 'https://github.com/NixOS/nixpkgs/commit/$1'); done

Related discussions

Justified addings of the option

  • Because there are multiple asterisk versions now: #22358
  • Because there are multiple btsync versions now: #7215
  • Because there are multiple datadog versions now: #40399
  • Because there are multiple foundationdb versions: 5a24d99
  • Because there are multiple gitlab-runner versions now: #24254
  • Because there are multiple apacheHttpd versions: 52c97ad
  • Because there are multiple quassel versions: #20159
  • Because there are multiple radicale versions now: #27826
  • Because there are multiple riak versions now: #7827
  • Because there are multiple samba versions: 8ec82fc
  • Because there are alternate sick... versions: #46607
  • Because there are multiple softether versions now: #29781
  • Because there are multiple syncthing versions now: #11329
  • Because there are multiple upower versions now: df95a8c
  • Because there are multiple varnish versions now: #37412
  • Because there are multiple bspwd versions: #20384

Commits/PRs that add the option without justification

Mostly these are probably just people not knowing they can use overlays to do it. I'm pinging all of you in the hopes that you see that overlays could have been used instead or to potentially find other reasons to introduce such an option.

23 Answers

✔️Accepted Answer

My vote is to put it in for all services that have a relevant notion of packages backing them. The main reason for this is that it's not always clear which packages are being used by a service (e.g., we have services.httpd which uses pkgs.apacheHttpd; yes the module lives in services/apache-httpd but in general nothing requires them to line up) so unless someone pokes at the nixpkgs source code, they don't necessarily know which module to override and there's no real feedback to figure out which was overridden other than hoping to see the .service unit get rebuilt if you got it right.

The reasons you give in favor of the field also factor into my preference. I'm already frustrated at how "singleton"-flavored our services all are, so forcing all of them to go through a single registry of versions seems annoying.

Other Answers:

The package option is quite convenient, it allows to select a different version without reading the module source or triggering too many rebuilds.

@joachifm I guess a nontrivial subset of Nixpkgs/NixOS developers have experience that unchangeable defaults end up in a state not fitting our needs. This leads to the ideal of having a lot of knobs that can be ignored if everything acceptable, but provide an escape hatch if something exotic/complicated is desired. Then it turns out there are evaluation time issues…

I might be wrong, as I don't use NixOS proper anymore, and I use only a reasonably small subset of NixOS module code. (A few unchangeable defaults ended p annoying me too much).

The package option is also useful for overrides or even using a different channel. Having to override the default attribute means there's no choice to do this in a contained way anymore. Even when using overlays I always do this instead.

{
  services.foo.package = pkgs.namespace.foo;
  nixpkgs.overlays = [(self: super: {
     namespace.foo = super.foo.override { withBar = true; };
  })];
}

I propose to close this issue and go toward adding package attribute to all the modules that are backed by a single package.

Without a proper benchmark it's not worth talking about hypothetical performance improvements. NixOS evaluation is highly sensitive to the disk cache and needs to be repeated many times.

On the other hand, having a consistent interface is useful on many levels. Like @copumpkin said, the user can rely on the option being there and not have to dig into the nixos source. Not everybody has write access to nixpkgs to add the package option "when needed".

More Issues: