"Implicitly" enabled NixOS modules are bad

Many many NixOS modules feature a .enable boolean option that controls whether the module’s configuration will be utilized.

Some modules however have no .enable option, and instead feature some random mkIf condition like mkIf cfg.extraConfig != "". I find this pretty problematic.

First of all, this hurts abstracting over modules. A utility function like utils.enableMultiple "programs" [ "foo" "bar" ] can’t work, because maybe the programs.bar module is “special” and depends on some random conditions to be enabled.

Second it hurts incidental module cooperation. Imagine the zsh module worked this way, with random condition on when to apply its configuration. Imagine you write yourself a git module that just contributes to programs.zsh.extraConfig. Oops, enabling your git module caused ZSH to get installed.

I understand if modules want to have secondary conditions that control how their config settings are defined. That makes total sense. But every module should have a top-level .enabled option that controls at least whether any of the rest of the internal module logic is considered.

Anyone else?

4 Likes

An enable option is not always appropriate: there are purely tasks or system configuration modules for which there is no service or program being installed.

For example, the option services.xserver.extraLayouts is implemented in the extra-layouts.nix file and installs keyboard layout. I would not expect having to explicitly enable this module to actually have extraLayouts.my-layout installed.

For programs and services, I agree, it would be better if all non-essential module had an enable option (preferably defined with mkEnableOption). However, it seems there are not that many such modules from a quick inspection:

find nixos/modules/services/ -type f ! -regex '.*-\(submodule\|options\)\.nix' \
  | xargs grep -lE 'options ?= ?\{' \
  | xargs grep -LE 'mkEnableOption|(mkIf .*((cfg|config)(\.[.a-zA-Z0-9-]+)?)\.enabled?)'

I agree with the point that most modules should have .enable.

When I wrote NixOS modules for our infrastructure, I initially didn’t do this for some services, and just yesterday got various problems from that, having to resort to cludgy conditional adding to imports [ ... ].

1 Like