Home Explore Blog CI



nixpkgs

nixos/doc/manual/configuration/abstractions.section.md
35cfa5a57921912977358ea6994200c6065f39968cd1efaf0000000300000ac2
# Abstractions {#sec-module-abstractions}

If you find yourself repeating yourself over and over, it’s time to abstract. Take, for instance, this Apache HTTP Server configuration:

```nix
{
  services.httpd.virtualHosts =
    { "blog.example.org" = {
        documentRoot = "/webroot/blog.example.org";
        adminAddr = "alice@example.org";
        forceSSL = true;
        enableACME = true;
      };
      "wiki.example.org" = {
        documentRoot = "/webroot/wiki.example.org";
        adminAddr = "alice@example.org";
        forceSSL = true;
        enableACME = true;
      };
    };
}
```

It defines two virtual hosts with nearly identical configuration; the only difference is the document root directories. To prevent this duplication, we can use a `let`:
```nix
let
  commonConfig =
    { adminAddr = "alice@example.org";
      forceSSL = true;
      enableACME = true;
    };
in
{
  services.httpd.virtualHosts =
    { "blog.example.org" = (commonConfig // { documentRoot = "/webroot/blog.example.org"; });
      "wiki.example.org" = (commonConfig // { documentRoot = "/webroot/wiki.example.org"; });
    };
}
```

The `let commonConfig = ...` defines a variable named `commonConfig`. The `//` operator merges two attribute sets, so the configuration of the second virtual host is the set `commonConfig` extended with the document root option.

You can write a `let` wherever an expression is allowed. Thus, you also could have written:

```nix
{
  services.httpd.virtualHosts =
    let commonConfig = { /* ... */ }; in
    { "blog.example.org" = (commonConfig // { /* ... */ });
      "wiki.example.org" = (commonConfig // { /* ... */ });
    };
}
```

but not `{ let commonConfig = ...; in ...; }` since attributes (as opposed to attribute values) are not expressions.

**Functions** provide another method of abstraction. For instance, suppose that we want to generate lots of different virtual hosts, all with identical configuration except for the document root. This can be done as follows:

```nix
{
  services.httpd.virtualHosts =
    let
      makeVirtualHost = webroot:
        { documentRoot = webroot;
          adminAddr = "alice@example.org";
          forceSSL = true;
          enableACME = true;
        };
    in
      { "example.org" = (makeVirtualHost "/webroot/example.org");
        "example.com" = (makeVirtualHost "/webroot/example.com");
        "example.gov" = (makeVirtualHost "/webroot/example.gov");
        "example.nl" = (makeVirtualHost "/webroot/example.nl");
      };
}
```

Here, `makeVirtualHost` is a function that takes a single argument `webroot` and returns the configuration for a virtual host. That function is then called for several names to produce the list of virtual host configurations.

Chunks
d1062ddc (1st chunk of `nixos/doc/manual/configuration/abstractions.section.md`)
Title: Abstraction Techniques in Nix: 'let' and Functions
Summary
This section discusses abstraction techniques in Nix, specifically using 'let' expressions and functions to avoid repetition in configurations. It demonstrates how to define common configurations using 'let' and merge them with specific options for different virtual hosts. It also shows how to create functions to generate configurations based on input parameters, like document root, further reducing redundancy and improving maintainability.