# Options for Program Settings {#sec-settings-options} Many programs have configuration files where program-specific settings can be declared. File formats can be separated into two categories: - Nix-representable ones: These can trivially be mapped to a subset of Nix syntax. E.g. JSON is an example, since its values like `{"foo":{"bar":10}}` can be mapped directly to Nix: `{ foo = { bar = 10; }; }`. Other examples are INI, YAML and TOML. The following section explains the convention for these settings. - Non-nix-representable ones: These can't be trivially mapped to a subset of Nix syntax. Most generic programming languages are in this group, e.g. bash, since the statement `if true; then echo hi; fi` doesn't have a trivial representation in Nix. Currently there are no fixed conventions for these, but it is common to have a `configFile` option for setting the configuration file path directly. The default value of `configFile` can be an auto-generated file, with convenient options for controlling the contents. For example an option of type `attrsOf str` can be used for representing environment variables which generates a section like `export FOO="foo"`. Often it can also be useful to also include an `extraConfig` option of type `lines` to allow arbitrary text after the autogenerated part of the file. ## Nix-representable Formats (JSON, YAML, TOML, INI, ...) {#sec-settings-nix-representable} By convention, formats like this are handled with a generic `settings` option, representing the full program configuration as a Nix value. The type of this option should represent the format. The most common formats have a predefined type and string generator already declared under `pkgs.formats`: `pkgs.formats.javaProperties` { *`comment`* ? `"Generated with Nix"` } : A function taking an attribute set with values `comment` : A string to put at the start of the file in a comment. It can have multiple lines. It returns the `type`: `attrsOf str` and a function `generate` to build a Java `.properties` file, taking care of the correct escaping, etc. `pkgs.formats.json` { } : A function taking an empty attribute set (for future extensibility) and returning a set with JSON-specific attributes `type` and `generate` as specified [below](#pkgs-formats-result). `pkgs.formats.yaml` { } : A function taking an empty attribute set (for future extensibility) and returning a set with YAML-specific attributes `type` and `generate` as specified [below](#pkgs-formats-result). `pkgs.formats.ini` { *`listsAsDuplicateKeys`* ? false, *`listToValue`* ? null, \... } : A function taking an attribute set with values `listsAsDuplicateKeys` : A boolean for controlling whether list values can be used to represent duplicate INI keys `listToValue` : A function for turning a list of values into a single value. It returns a set with INI-specific attributes `type` and `generate` as specified [below](#pkgs-formats-result). `pkgs.formats.toml` { } : A function taking an empty attribute set (for future extensibility) and returning a set with TOML-specific attributes `type` and `generate` as specified [below](#pkgs-formats-result). `pkgs.formats.elixirConf { elixir ? pkgs.elixir }` : A function taking an attribute set with values `elixir` : The Elixir package which will be used to format the generated output It returns a set with Elixir-Config-specific attributes `type`, `lib`, and `generate` as specified [below](#pkgs-formats-result). The `lib` attribute contains functions to be used in settings, for generating special Elixir values: `mkRaw elixirCode` : Outputs the given string as raw Elixir code `mkGetEnv { envVariable, fallback ? null }` : Makes the configuration fetch an environment variable at runtime `mkAtom atom` : Outputs the given string as an Elixir atom, instead of the default Elixir binary string. Note: lowercase atoms still needs to be prefixed with `:` `mkTuple array` : Outputs the given array as an Elixir tuple, instead of the default Elixir list `mkMap attrset` : Outputs the given attribute set as an Elixir map, instead of the default Elixir keyword list ::: {#pkgs-formats-result} These functions all return an attribute set with these values: ::: `type` : A module system type representing a value of the format `lib` : Utility functions for convenience, or special interactions with the format. This attribute is optional. It may contain inside a `types` attribute containing types specific to this format. `generate` *`filename jsonValue`* : A function that can render a value of the format to a file. Returns a file path. ::: {.note} This function puts the value contents in the Nix store. So this should be avoided for secrets. ::: ::: {#ex-settings-nix-representable .example} ::: {.title} **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 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} ::: {.title} **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 for supported values. ''; }; ``` :::