R""(

nix flake provides subcommands for creating, modifying and querying Nix flakes. Flakes are the unit for packaging Nix code in a reproducible and discoverable way. They can have dependencies on other flakes, making it possible to have multi-repository Nix projects.

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).

Flake references (flakerefs) are a way to specify the location of a flake. These have two different forms:

Example:

{
  type = "github";
  owner = "NixOS";
  repo = "nixpkgs";
}

The only required attribute is type. The supported types are listed below.

Example:

github:NixOS/nixpkgs

These are used on the command line as a more convenient alternative to the attribute set representation. For instance, in the command

# nix build github:NixOS/nixpkgs#hello

github:NixOS/nixpkgs is a flake reference (while hello is an output attribute). They are also allowed in the inputs attribute of a flake, e.g.

inputs.nixpkgs.url = "github:NixOS/nixpkgs";

is equivalent to

inputs.nixpkgs = {
  type = "github";
  owner = "NixOS";
  repo = "nixpkgs";
};

Here are some examples of flake references in their URL-like representation:

Flakes corresponding to a local path can also be referred to by a direct path reference, either /absolute/path/to/the/flake or ./relative/path/to/the/flake (note that the leading ./ is mandatory for relative paths to avoid any ambiguity).

The semantic of such a path is as follows:

The following generic flake reference attributes are supported:

In addition, the following attributes are common to several flake reference types:

Finally, some attribute are typically not specified by the user, but can occur in locked flake references and are available to Nix code:

Currently the type attribute can be one of the following:

As an example, here is a simple flake.nix that depends on the Nixpkgs flake and provides a single package (i.e. an installable derivation):

{
  description = "A flake for building Hello World";

  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-20.03";

  outputs = { self, nixpkgs }: {

    packages.x86_64-linux.default =
      # Notice the reference to nixpkgs here.
      with import nixpkgs { system = "x86_64-linux"; };
      stdenv.mkDerivation {
        name = "hello";
        src = self;
        buildPhase = "gcc -o hello ./hello.c";
        installPhase = "mkdir -p $out/bin; install -t $out/bin hello";
      };

  };
}

The following attributes are supported in flake.nix:

The attribute inputs specifies the dependencies of a flake, as an attrset mapping input names to flake references. For example, the following specifies a dependency on the nixpkgs and import-cargo repositories:

# A GitHub repository.
inputs.import-cargo = {
  type = "github";
  owner = "edolstra";
  repo = "import-cargo";
};

# An indirection through the flake registry.
inputs.nixpkgs = {
  type = "indirect";
  id = "nixpkgs";
};

Alternatively, you can use the URL-like syntax:

inputs.import-cargo.url = "github:edolstra/import-cargo";
inputs.nixpkgs.url = "nixpkgs";

Each input is fetched, evaluated and passed to the outputs function as a set of attributes with the same name as the corresponding input. The special input named self refers to the outputs and source tree of this flake. Thus, a typical outputs function looks like this:

outputs = { self, nixpkgs, import-cargo }: {
  ... outputs ...
};

It is also possible to omit an input entirely and only list it as expected function argument to outputs. Thus,

outputs = { self, nixpkgs }: ...;

without an inputs.nixpkgs attribute is equivalent to

inputs.nixpkgs = {
  type = "indirect";
  id = "nixpkgs";
};

Repositories that don't contain a flake.nix can also be used as inputs, by setting the input's flake attribute to false:

inputs.grcov = {
  type = "github";
  owner = "mozilla";
  repo = "grcov";
  flake = false;
};

outputs = { self, nixpkgs, grcov }: {
  packages.x86_64-linux.grcov = stdenv.mkDerivation {
    src = grcov;
    ...
  };
};

Transitive inputs can be overridden from a flake.nix file. For example, the following overrides the nixpkgs input of the nixops input:

inputs.nixops.inputs.nixpkgs = {
  type = "github";
  owner = "my-org";
  repo = "nixpkgs";
};

It is also possible to "inherit" an input from another input. This is useful to minimize flake dependencies. For example, the following sets the nixpkgs input of the top-level flake to be equal to the nixpkgs input of the dwarffs input of the top-level flake:

inputs.nixpkgs.follows = "dwarffs/nixpkgs";

The value of the follows attribute is a /-separated sequence of input names denoting the path of inputs to be followed from the root flake.

Overrides and follows can be combined, e.g.

inputs.nixops.inputs.nixpkgs.follows = "dwarffs/nixpkgs";

sets the nixpkgs input of nixops to be the same as the nixpkgs input of dwarffs. It is worth noting, however, that it is generally not useful to eliminate transitive nixpkgs flake inputs in this way. Most flakes provide their functionality through Nixpkgs overlays or NixOS modules, which are composed into the top-level flake's nixpkgs input; so their own nixpkgs input is usually irrelevant.

Inputs specified in flake.nix are typically "unlocked" in the sense that they don't specify an exact revision. To ensure reproducibility, Nix will automatically generate and use a lock file called flake.lock in the flake's directory. The lock file contains a graph structure isomorphic to the graph of dependencies of the root flake. Each node in the graph (except the root node) maps the (usually) unlocked input specifications in flake.nix to locked input specifications. Each node also contains some metadata, such as the dependencies (outgoing edges) of the node.

For example, if flake.nix has the inputs in the example above, then the resulting lock file might be:

{
  "version": 7,
  "root": "n1",
  "nodes": {
    "n1": {
      "inputs": {
        "nixpkgs": "n2",
        "import-cargo": "n3",
        "grcov": "n4"
      }
    },
    "n2": {
      "inputs": {},
      "locked": {
        "owner": "edolstra",
        "repo": "nixpkgs",
        "rev": "7f8d4b088e2df7fdb6b513bc2d6941f1d422a013",
        "type": "github",
        "lastModified": 1580555482,
        "narHash": "sha256-OnpEWzNxF/AU4KlqBXM2s5PWvfI5/BS6xQrPvkF5tO8="
      },
      "original": {
        "id": "nixpkgs",
        "type": "indirect"
      }
    },
    "n3": {
      "inputs": {},
      "locked": {
        "owner": "edolstra",
        "repo": "import-cargo",
        "rev": "8abf7b3a8cbe1c8a885391f826357a74d382a422",
        "type": "github",
        "lastModified": 1567183309,
        "narHash": "sha256-wIXWOpX9rRjK5NDsL6WzuuBJl2R0kUCnlpZUrASykSc="
      },
      "original": {
        "owner": "edolstra",
        "repo": "import-cargo",
        "type": "github"
      }
    },
    "n4": {
      "inputs": {},
      "locked": {
        "owner": "mozilla",
        "repo": "grcov",
        "rev": "989a84bb29e95e392589c4e73c29189fd69a1d4e",
        "type": "github",
        "lastModified": 1580729070,
        "narHash": "sha256-235uMxYlHxJ5y92EXZWAYEsEb6mm+b069GAd+BOIOxI="
      },
      "original": {
        "owner": "mozilla",
        "repo": "grcov",
        "type": "github"
      },
      "flake": false
    }
  }
}

This graph has 4 nodes: the root flake, and its 3 dependencies. The nodes have arbitrary labels (e.g. n1). The label of the root node of the graph is specified by the root attribute. Nodes contain the following fields:

The original and locked attributes are omitted for the root node. This is because we cannot record the commit hash or content hash of the root flake, since modifying flake.lock will invalidate these.

The graph representation of lock files allows circular dependencies between flakes. For example, here are two flakes that reference each other:

{
  inputs.b = ... location of flake B ...;
  # Tell the 'b' flake not to fetch 'a' again, to ensure its 'a' is
  # *this* 'a'.
  inputs.b.inputs.a.follows = "";
  outputs = { self, b }: {
    foo = 123 + b.bar;
    xyzzy = 1000;
  };
}

and

{
  inputs.a = ... location of flake A ...;
  inputs.a.inputs.b.follows = "";
  outputs = { self, a }: {
    bar = 456 + a.xyzzy;
  };
}

Lock files transitively lock direct as well as indirect dependencies. That is, if a lock file exists and is up to date, Nix will not look at the lock files of dependencies. However, lock file generation itself does use the lock files of dependencies by default.

)""