Reference diagram for nix file/module/flake/function use cases and identification

I’m still climbing Nix’s cliff of an onboarding process (I’m guessing I’m about halfway up).

One thing I’m having a some trouble pinning down in my mind is exactly what a module is in relation to a flake, and how both of those interact with nix files, functions, and expressions. And what can include what else in each other. (I think mainly because all these things don’t have easily readable “THIS IS A MODULE/FUNCTION/FLAKE” lines at the top of a file, and instead must be inferred from structure)

Are there any convenient reference diagrams that show the relations between these things, and how to identify them if I’m looking at them?

As near as I can tell so far:

  • All .nix files are nix expressions
  • A .nix file may be a function
  • A .nix file may be a module
    • A module may also be a function
  • A .nix file may be a flake
    • Every flake is a function
  • A nix expression can include another .nix file with the builtin include function
  • A nix module can include other modules with the different-from-the-builtin includes list of other modules.
  • Flakes can include modules
  • Flakes can include other flakes
  • Flakes can produce modules as output?

Having all this stuff in quick-reference diagram form would be really helpful

To be pedantic, files are objects on a file system. Their content should be a Nix expression – though file names are just convention, we cannot prevent anyone from saving e.g. a borked Nix expressions or an image with Nix logo as a file with .nix extension.

An expression can be a function. You can find all kinds of expression in the Nix manual or in this tutorial.

Yes, a NixOS module is a Nix expression. It must evaluate into either an attribute set of specific shape, or a function that returns such attribute set. Note that it only has to evaluate into those, the following expression is a valid NixOS module, even though the top-level Nix expression is neither:

let
  hostname = "london";
in
{ pkgs, ... }:
{
  # …  
}

I would say flake is the virtual object described by the flake manifest (flake.nix file) but I do not think the terminology is settled. The Nix manual has more materialistic definition:

A flake is a filesystem tree (typically fetched from a Git repository or a tarball) that contains a file named flake.nix in the root directory. flake.nix specifies some metadata about the flake such as dependencies (called inputs), as well as its outputs (the Nix values such as packages or NixOS modules provided by the flake).

And then later uses the same term for flake.nix.

No. The flake.nix file uses a subset of Nix syntax, where the top-level expression can only be an attribute set. Unlike in NixOS modules, evaluating to an attribute set is not enough.

Yes. It is builtins.import (or import) for short.

Right. See this discussion for the differences.

A flake can provide various outputs. NixOS modules are one of the output kinds (example). NixOS modules can import other NixOS modules.

A flake can also contain NixOS system outputs. NixOS system configurations are actually NixOS modules themselves so they can also import NixOS modules.

Flakes can declare other flakes as inputs, which will then be available as arguments to the outputs function inside flake.nix.

2 Likes