1 2# Writing and Reviewing Modular Services 3 4## Status 5 6Modular Services are, as of writing, a new feature with support in NixOS. 7It is in development, and be considerate of the fact that the intermediate outcome of RFC 163 is that we should try a module-based approach to portable services; it is not yet a widely agreed upon solution. 8 9## Relation to NixOS Modules 10 11- A modular service is not a replacement for a NixOS module, but may be in the future. 12- Using a modular service to implement a NixOS module is an expected use case, but exposes the NixOS module to a degree of uncertainty that is not acceptable for widely used modules yet. 13 14## Maintainership 15 16If you contribute a modular service, you must mark yourself as maintainer of the modular service. 17The maintainership of a modular service does not need to be the same as the maintainership of a NixOS module. 18If you are not a maintainer of the NixOS module, you should offer to join the NixOS module's `meta.maintainers` team, so that you are included in reviews and discussions, most of which also affect the modular service. 19The NixOS module maintainers have no obligation towards the modular service, except perhaps to notify you if they notice that the modular service breaks. 20 21## Minimum Standard 22 23Modular services **MUST** be accompanied by a **NixOS VM test** that exercises the modular service. 24 25Modular services **MUST** have a `meta.maintainers` module attribute that lists the maintainers of the modular service. 26 27## Reviewing Modular Services 28 29When reviewing a modular service, you should check the following. Details and rationale are provided below. 30 31```markdown 32- [ ] Has a NixOS VM test 33- [ ] Has a `meta.maintainers` attribute 34- [ ] Systemd-specific definitions are behind `optionalAttrs (options ? systemd)` to promote portability. 35- [ ] `_class = "service"` 36- [ ] Modular services provided through `passthru.services` must override the default of the package option using `finalAttrs.finalPackage` 37- [ ] Is the modular services infrastructure sufficient for this service? If one or more features are not covered, comment in https://github.com/NixOS/nixpkgs/issues/428084 38``` 39 40## Details 41 42### NixOS VM test 43 44See the initial [Modular Services PR](https://github.com/NixOS/nixpkgs/pull/372170) for an [example](https://github.com/NixOS/nixpkgs/pull/372170/files#diff-e7fe16489cf3cd08ecc22b2c7896039d407a329b75691c046c95447423b3153f) of a NixOS VM test. 45TBD: describe best practices here. 46 47### `_class = "service"` 48 49A [`_class`](https://nixos.org/manual/nixpkgs/unstable/#module-system-lib-evalModules-param-class) declaration ensures a clear error when the module is accidentally imported into a configuration that isn't a modular service, such as a NixOS configuration. 50 51Provide it as the first attribute in the module: 52 53```nix 54# Non-module dependencies (`importApply`) 55{ writeScript, runtimeShell }: 56 57# Service module 58{ lib, config, ... }: 59{ 60 _class = "service"; 61 62 options = { 63 # ... 64 }; 65 config = { 66 # ... 67 }; 68} 69``` 70 71### Overriding the package default 72 73When a modular service is provided through `passthru.services`, it must override the default of the package option using [`finalAttrs.finalPackage`](https://nixos.org/manual/nixpkgs/unstable/#mkderivation-recursive-attributes). 74If this is not possible, or if the module is not represented by a single package, consider exposing the modular service directly by file path only. 75 76Otherwise, since some packages are *defined* by an override, the modular service would launch a wrong package, if it builds at all. 77 78Example: 79 80`package.nix` 81```nix 82{ 83 stdenv, 84 nixosTests, 85# ... 86}: 87stdenv.mkDerivation (finalAttrs: { 88 pname = "example"; 89 # ... 90 91 passthru = { 92 services = { 93 default = { 94 imports = [ (lib.modules.importApply ./service.nix { inherit pkgs; }) ]; 95 example.package = finalAttrs.finalPackage; 96 # ... 97 }; 98 }; 99 }; 100}) 101```