Home Explore Blog Models CI



nixpkgs

7th chunk of `nixos/doc/manual/development/settings-options.section.md`
c3df1851e7e56b1392ee5ef41fc2a2f11e5a615c5b9f4e990000000100000c8a
::: {#ex-settings-nix-representable .example}
### Module with conventional `settings` option

The following shows a module for an example program that uses a JSON
configuration file. It demonstrates how above values can be used, along
with some other related best practices. See the comments for
explanations.

```nix
{
  options,
  config,
  lib,
  pkgs,
  ...
}:
let
  cfg = config.services.foo;
  # Define the settings format used for this program
  settingsFormat = pkgs.formats.json { };
in
{

  options.services.foo = {
    enable = lib.mkEnableOption "foo service";

    settings = lib.mkOption {
      # Setting this type allows for correct merging behavior
      type = settingsFormat.type;
      default = { };
      description = ''
        Configuration for foo, see
        <link xlink:href="https://example.com/docs/foo"/>
        for supported settings.
      '';
    };
  };

  config = lib.mkIf cfg.enable {
    # We can assign some default settings here to make the service work by just
    # enabling it. We use `mkDefault` for values that can be changed without
    # problems
    services.foo.settings = {
      # Fails at runtime without any value set
      log_level = lib.mkDefault "WARN";

      # We assume systemd's `StateDirectory` is used, so we require this value,
      # therefore no mkDefault
      data_path = "/var/lib/foo";

      # Since we use this to create a user we need to know the default value at
      # eval time
      user = lib.mkDefault "foo";
    };

    environment.etc."foo.json".source =
      # The formats generator function takes a filename and the Nix value
      # representing the format value and produces a filepath with that value
      # rendered in the format
      settingsFormat.generate "foo-config.json" cfg.settings;

    # We know that the `user` attribute exists because we set a default value
    # for it above, allowing us to use it without worries here
    users.users.${cfg.settings.user} = {
      isSystemUser = true;
    };

    # ...
  };
}
```
:::

### Option declarations for attributes {#sec-settings-attrs-options}

Some `settings` attributes may deserve some extra care. They may need a
different type, default or merging behavior, or they are essential
options that should show their documentation in the manual. This can be
done using [](#sec-freeform-modules).

We extend above example using freeform modules to declare an option for
the port, which will enforce it to be a valid integer and make it show
up in the manual.

::: {#ex-settings-typed-attrs .example}
### Declaring a type-checked `settings` attribute
```nix
{
  settings = lib.mkOption {
    type = lib.types.submodule {

      freeformType = settingsFormat.type;

      # Declare an option for the port such that the type is checked and this option
      # is shown in the manual.
      options.port = lib.mkOption {
        type = lib.types.port;
        default = 8080;
        description = ''
          Which port this service should listen on.
        '';
      };

    };
    default = { };
    description = ''
      Configuration for Foo, see
      <link xlink:href="https://example.com/docs/foo"/>
      for supported values.
    '';
  };
}
```
:::

Title: Nix Module Configuration Best Practices: Formats, Default Settings, and Type-Checked Attributes
Summary
This chunk presents an extended Nix module example for a 'foo' service, demonstrating how to use `pkgs.formats.json` to define a `settingsFormat` for its configuration. It shows how to assign default values to service settings (like `log_level`, `data_path`, and `user`) using `lib.mkDefault` and how to generate the final configuration file (`foo.json`) using `settingsFormat.generate`. The example also illustrates using a setting's value (`cfg.settings.user`) to configure other parts of the system, such as creating a system user. Following this, the document introduces the concept of declaring specific `settings` attributes as options using freeform modules (`lib.types.submodule` with `freeformType`), which allows for type checking (e.g., `lib.types.port` for a `port` option) and documenting these attributes directly in the manual.