.\" -*- mode: troff; coding: utf-8 -*- .TH "nix3-flake" "1" "" .RS .PP \fBWarning\fR .br This program is \fB\fBexperimental\fR\fR and its interface is subject to change. .RE .SH Name .LP \f(CRnix flake\fR - manage Nix flakes .SH Synopsis .LP \f(CRnix flake\fR [\fIoption\fR\[u2026]] \fIsubcommand\fR .PP where \fIsubcommand\fR is one of the following: .IP "\(bu" 3 \fB\f(CRnix flake archive\fR\fR - copy a flake and all its inputs to a store .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \fB\f(CRnix flake check\fR\fR - check whether the flake evaluates and run its tests .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \fB\f(CRnix flake clone\fR\fR - clone flake repository .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \fB\f(CRnix flake info\fR\fR - show flake metadata .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \fB\f(CRnix flake init\fR\fR - create a flake in the current directory from a template .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \fB\f(CRnix flake lock\fR\fR - create missing lock file entries .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \fB\f(CRnix flake metadata\fR\fR - show flake metadata .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \fB\f(CRnix flake new\fR\fR - create a flake in the specified directory from a template .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \fB\f(CRnix flake prefetch\fR\fR - download the source tree denoted by a flake reference into the Nix store .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \fB\f(CRnix flake show\fR\fR - show the outputs provided by a flake .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \fB\f(CRnix flake update\fR\fR - update flake lock file .SH Description .LP \f(CRnix flake\fR provides subcommands for creating, modifying and querying \fINix flakes\fR. 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. .PP A flake is a filesystem tree (typically fetched from a Git repository or a tarball) that contains a file named \f(CRflake.nix\fR in the root directory. \f(CRflake.nix\fR specifies some metadata about the flake such as dependencies (called \fIinputs\fR), as well as its \fIoutputs\fR (the Nix values such as packages or NixOS modules provided by the flake). .SH Flake references .LP Flake references (\fIflakerefs\fR) are a way to specify the location of a flake. These have two different forms: .SS Attribute set representation .LP Example: .LP .EX { type = \(dqgithub\(dq; owner = \(dqNixOS\(dq; repo = \(dqnixpkgs\(dq; } .EE .PP The only required attribute is \f(CRtype\fR. The supported types are listed below. .SS URL-like syntax .LP Example: .LP .EX github:NixOS/nixpkgs .EE .PP These are used on the command line as a more convenient alternative to the attribute set representation. For instance, in the command .LP .EX # nix build github:NixOS/nixpkgs#hello .EE .PP \f(CRgithub:NixOS/nixpkgs\fR is a flake reference (while \f(CRhello\fR is an output attribute). They are also allowed in the \f(CRinputs\fR attribute of a flake, e.g. .LP .EX inputs.nixpkgs.url = \(dqgithub:NixOS/nixpkgs\(dq; .EE .PP is equivalent to .LP .EX inputs.nixpkgs = { type = \(dqgithub\(dq; owner = \(dqNixOS\(dq; repo = \(dqnixpkgs\(dq; }; .EE .SS Examples .LP Here are some examples of flake references in their URL-like representation: .IP "\(bu" 3 \f(CRnixpkgs\fR: The \f(CRnixpkgs\fR entry in the flake registry. .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \f(CRnixpkgs/a3a3dda3bacf61e8a39258a0ed9c924eeca8e293\fR: The \f(CRnixpkgs\fR entry in the flake registry, with its Git revision overridden to a specific value. .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \f(CRgithub:NixOS/nixpkgs\fR: The \f(CRmaster\fR branch of the \f(CRNixOS/nixpkgs\fR repository on GitHub. .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \f(CRgithub:NixOS/nixpkgs/nixos-20.09\fR: The \f(CRnixos-20.09\fR branch of the \f(CRnixpkgs\fR repository. .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \f(CRgithub:NixOS/nixpkgs/a3a3dda3bacf61e8a39258a0ed9c924eeca8e293\fR: A specific revision of the \f(CRnixpkgs\fR repository. .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \f(CRgithub:edolstra/nix-warez?dir=blender\fR: A flake in a subdirectory of a GitHub repository. .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \f(CRgit+https://github.com/NixOS/patchelf\fR: A Git repository. .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \f(CRgit+https://github.com/NixOS/patchelf?ref=master\fR: A specific branch of a Git repository. .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \f(CRgit+https://github.com/NixOS/patchelf?ref=master&rev=f34751b88bd07d7f44f5cd3200fb4122bf916c7e\fR: A specific branch \fIand\fR revision of a Git repository. .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \f(CRhttps://github.com/NixOS/patchelf/archive/master.tar.gz\fR: A tarball flake. .SS Path-like syntax .LP Flakes corresponding to a local path can also be referred to by a direct path reference, either \f(CR/absolute/path/to/the/flake\fR or \f(CR./relative/path/to/the/flake\fR (note that the leading \f(CR./\fR is mandatory for relative paths to avoid any ambiguity). .PP The semantic of such a path is as follows: .IP "\(bu" 3 If the directory is part of a Git repository, then the input will be treated as a \f(CRgit+file:\fR URL, otherwise it will be treated as a \f(CRpath:\fR url; .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 If the directory doesn\(cqt contain a \f(CRflake.nix\fR file, then Nix will search for such a file upwards in the file system hierarchy until it finds any of: .RS .IP "1." 3 The Git repository root, or .if n \ .sp -1 .if t \ .sp -0.25v .IP "2." 3 The filesystem root (/), or .if n \ .sp -1 .if t \ .sp -0.25v .IP "3." 3 A folder on a different mount point. .RE .SS Examples .IP "\(bu" 3 \f(CR.\fR: The flake to which the current directory belongs to. .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \f(CR/home/alice/src/patchelf\fR: A flake in some other directory. .SS Flake reference attributes .LP The following generic flake reference attributes are supported: .IP "\(bu" 3 \f(CRdir\fR: The subdirectory of the flake in which \f(CRflake.nix\fR is located. This parameter enables having multiple flakes in a repository or tarball. The default is the root directory of the flake. .IP "\(bu" 3 \f(CRnarHash\fR: The hash of the NAR serialisation (in SRI format) of the contents of the flake. This is useful for flake types such as tarballs that lack a unique content identifier such as a Git commit hash. .LP In addition, the following attributes are common to several flake reference types: .IP "\(bu" 3 \f(CRrev\fR: A Git or Mercurial commit hash. .IP "\(bu" 3 \f(CRref\fR: A Git or Mercurial branch or tag name. .LP Finally, some attribute are typically not specified by the user, but can occur in \fIlocked\fR flake references and are available to Nix code: .IP "\(bu" 3 \f(CRrevCount\fR: The number of ancestors of the commit \f(CRrev\fR. .IP "\(bu" 3 \f(CRlastModified\fR: The timestamp (in seconds since the Unix epoch) of the last modification of this version of the flake. For Git/Mercurial flakes, this is the commit time of commit \fIrev\fR, while for tarball flakes, it\(cqs the most recent timestamp of any file inside the tarball. .SS Types .LP Currently the \f(CRtype\fR attribute can be one of the following: .IP "\(bu" 3 \f(CRpath\fR: arbitrary local directories, or local Git trees. The required attribute \f(CRpath\fR specifies the path of the flake. The URL form is .LP .EX [path:](\e?)?(\e?)? .EE .IP The \f(CRref\fR attribute defaults to resolving the \f(CRHEAD\fR reference. .IP The \f(CRrev\fR attribute must denote a commit that exists in the branch or tag specified by the \f(CRref\fR attribute, since Nix doesn\(cqt do a full clone of the remote repository by default (and the Git protocol doesn\(cqt allow fetching a \f(CRrev\fR without a known \f(CRref\fR). The default is the commit currently pointed to by \f(CRref\fR. .IP When \f(CRgit+file\fR is used without specifying \f(CRref\fR or \f(CRrev\fR, files are fetched directly from the local \f(CRpath\fR as long as they have been added to the Git repository. If there are uncommitted changes, the reference is treated as dirty and a warning is printed. .IP For example, the following are valid Git flake references: .RS .IP "\(bu" 3 \f(CRgit+https://example.org/my/repo\fR .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \f(CRgit+https://example.org/my/repo?dir=flake1\fR .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \f(CRgit+ssh://git@github.com/NixOS/nix?ref=v1.2.3\fR .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \f(CRgit://github.com/edolstra/dwarffs?ref=unstable&rev=e486d8d40e626a20e06d792db8cc5ac5aba9a5b4\fR .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \f(CRgit+file:///home/my-user/some-repo/some-repo\fR .RE .IP "\(bu" 3 \f(CRmercurial\fR: Mercurial repositories. The URL form is similar to the \f(CRgit\fR type, except that the URL schema must be one of \f(CRhg+http\fR, \f(CRhg+https\fR, \f(CRhg+ssh\fR or \f(CRhg+file\fR. .IP "\(bu" 3 \f(CRtarball\fR: Tarballs. The location of the tarball is specified by the attribute \f(CRurl\fR. .IP In URL form, the schema must be \f(CRtarball+http://\fR, \f(CRtarball+https://\fR or \f(CRtarball+file://\fR. If the extension corresponds to a known archive format (\f(CR.zip\fR, \f(CR.tar\fR, \f(CR.tgz\fR, \f(CR.tar.gz\fR, \f(CR.tar.xz\fR, \f(CR.tar.bz2\fR or \f(CR.tar.zst\fR), then the \f(CRtarball+\fR can be dropped. .IP "\(bu" 3 \f(CRfile\fR: Plain files or directory tarballs, either over http(s) or from the local disk. .IP In URL form, the schema must be \f(CRfile+http://\fR, \f(CRfile+https://\fR or \f(CRfile+file://\fR. If the extension doesn’t correspond to a known archive format (as defined by the \f(CRtarball\fR fetcher), then the \f(CRfile+\fR prefix can be dropped. .IP "\(bu" 3 \f(CRgithub\fR: A more efficient way to fetch repositories from GitHub. The following attributes are required: .RS .IP "\(bu" 3 \f(CRowner\fR: The owner of the repository. .IP "\(bu" 3 \f(CRrepo\fR: The name of the repository. .RE .IP These are downloaded as tarball archives, rather than through Git. This is often much faster and uses less disk space since it doesn\(cqt require fetching the entire history of the repository. On the other hand, it doesn\(cqt allow incremental fetching (but full downloads are often faster than incremental fetches!). .IP The URL syntax for \f(CRgithub\fR flakes is: .LP .EX github:/(/)?(\e?)? .EE .IP \f(CR\fR specifies the name of a branch or tag (\f(CRref\fR), or a commit hash (\f(CRrev\fR). Note that unlike Git, GitHub allows fetching by commit hash without specifying a branch or tag. .IP You can also specify \f(CRhost\fR as a parameter, to point to a custom GitHub Enterprise server. .IP Some examples: .RS .IP "\(bu" 3 \f(CRgithub:edolstra/dwarffs\fR .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \f(CRgithub:edolstra/dwarffs/unstable\fR .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \f(CRgithub:edolstra/dwarffs/d3f2baba8f425779026c6ec04021b2e927f61e31\fR .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \f(CRgithub:internal/project?host=company-github.example.org\fR .RE .IP "\(bu" 3 \f(CRgitlab\fR: Similar to \f(CRgithub\fR, is a more efficient way to fetch GitLab repositories. The following attributes are required: .RS .IP "\(bu" 3 \f(CRowner\fR: The owner of the repository. .IP "\(bu" 3 \f(CRrepo\fR: The name of the repository. .RE .IP Like \f(CRgithub\fR, these are downloaded as tarball archives. .IP The URL syntax for \f(CRgitlab\fR flakes is: .IP \f(CRgitlab:/(/)?(\e?)?\fR .IP \f(CR\fR works the same as \f(CRgithub\fR. Either a branch or tag name (\f(CRref\fR), or a commit hash (\f(CRrev\fR) can be specified. .IP Since GitLab allows for self-hosting, you can specify \f(CRhost\fR as a parameter, to point to any instances other than \f(CRgitlab.com\fR. .IP Some examples: .RS .IP "\(bu" 3 \f(CRgitlab:veloren/veloren\fR .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \f(CRgitlab:veloren/veloren/master\fR .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \f(CRgitlab:veloren/veloren/80a4d7f13492d916e47d6195be23acae8001985a\fR .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \f(CRgitlab:openldap/openldap?host=git.openldap.org\fR .RE .IP When accessing a project in a (nested) subgroup, make sure to URL-encode any slashes, i.e. replace \f(CR/\fR with \f(CR%2F\fR: .RS .IP "\(bu" 3 \f(CRgitlab:veloren%2Fdev/rfcs\fR .RE .IP "\(bu" 3 \f(CRsourcehut\fR: Similar to \f(CRgithub\fR, is a more efficient way to fetch SourceHut repositories. The following attributes are required: .RS .IP "\(bu" 3 \f(CRowner\fR: The owner of the repository (including leading \f(CR\(ti\fR). .IP "\(bu" 3 \f(CRrepo\fR: The name of the repository. .RE .IP Like \f(CRgithub\fR, these are downloaded as tarball archives. .IP The URL syntax for \f(CRsourcehut\fR flakes is: .IP \f(CRsourcehut:/(/)?(\e?)?\fR .IP \f(CR\fR works the same as \f(CRgithub\fR. Either a branch or tag name (\f(CRref\fR), or a commit hash (\f(CRrev\fR) can be specified. .IP Since SourceHut allows for self-hosting, you can specify \f(CRhost\fR as a parameter, to point to any instances other than \f(CRgit.sr.ht\fR. .IP Currently, \f(CRref\fR name resolution only works for Git repositories. You can refer to Mercurial repositories by simply changing \f(CRhost\fR to \f(CRhg.sr.ht\fR (or any other Mercurial instance). With the caveat that you must explicitly specify a commit hash (\f(CRrev\fR). .IP Some examples: .RS .IP "\(bu" 3 \f(CRsourcehut:\(timisterio/nix-colors\fR .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \f(CRsourcehut:\(timisterio/nix-colors/main\fR .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \f(CRsourcehut:\(timisterio/nix-colors?host=git.example.org\fR .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \f(CRsourcehut:\(timisterio/nix-colors/182b4b8709b8ffe4e9774a4c5d6877bf6bb9a21c\fR .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \f(CRsourcehut:\(timisterio/nix-colors/21c1a380a6915d890d408e9f22203436a35bb2de?host=hg.sr.ht\fR .RE .IP "\(bu" 3 \f(CRindirect\fR: Indirections through the flake registry. These have the form .LP .EX [flake:](/(/rev)?)? .EE .IP These perform a lookup of \f(CR\fR in the flake registry. For example, \f(CRnixpkgs\fR and \f(CRnixpkgs/release-20.09\fR are indirect flake references. The specified \f(CRrev\fR and/or \f(CRref\fR are merged with the entry in the registry; see \fBnix registry\fR for details. .SH Flake format .LP As an example, here is a simple \f(CRflake.nix\fR that depends on the Nixpkgs flake and provides a single package (i.e. an \fBinstallable\fR derivation): .LP .EX { description = \(dqA flake for building Hello World\(dq; inputs.nixpkgs.url = \(dqgithub:NixOS/nixpkgs/nixos-20.03\(dq; outputs = { self, nixpkgs }: { packages.x86_64-linux.default = # Notice the reference to nixpkgs here. with import nixpkgs { system = \(dqx86_64-linux\(dq; }; stdenv.mkDerivation { name = \(dqhello\(dq; src = self; buildPhase = \(dqgcc -o hello ./hello.c\(dq; installPhase = \(dqmkdir -p $out/bin; install -t $out/bin hello\(dq; }; }; } .EE .PP The following attributes are supported in \f(CRflake.nix\fR: .IP "\(bu" 3 \f(CRdescription\fR: A short, one-line description of the flake. .IP "\(bu" 3 \f(CRinputs\fR: An attrset specifying the dependencies of the flake (described below). .IP "\(bu" 3 \f(CRoutputs\fR: A function that, given an attribute set containing the outputs of each of the input flakes keyed by their identifier, yields the Nix values provided by this flake. Thus, in the example above, \f(CRinputs.nixpkgs\fR contains the result of the call to the \f(CRoutputs\fR function of the \f(CRnixpkgs\fR flake. .IP In addition to the outputs of each input, each input in \f(CRinputs\fR also contains some metadata about the inputs. These are: .RS .IP "\(bu" 3 \f(CRoutPath\fR: The path in the Nix store of the flake\(cqs source tree. This way, the attribute set can be passed to \f(CRimport\fR as if it was a path, as in the example above (\f(CRimport nixpkgs\fR). .IP "\(bu" 3 \f(CRrev\fR: The commit hash of the flake\(cqs repository, if applicable. .IP "\(bu" 3 \f(CRrevCount\fR: The number of ancestors of the revision \f(CRrev\fR. This is not available for \f(CRgithub\fR repositories, since they\(cqre fetched as tarballs rather than as Git repositories. .IP "\(bu" 3 \f(CRlastModifiedDate\fR: The commit time of the revision \f(CRrev\fR, in the format \f(CR%Y%m%d%H%M%S\fR (e.g. \f(CR20181231100934\fR). Unlike \f(CRrevCount\fR, this is available for both Git and GitHub repositories, so it\(cqs useful for generating (hopefully) monotonically increasing version strings. .IP "\(bu" 3 \f(CRlastModified\fR: The commit time of the revision \f(CRrev\fR as an integer denoting the number of seconds since 1970. .IP "\(bu" 3 \f(CRnarHash\fR: The SHA-256 (in SRI format) of the NAR serialization of the flake\(cqs source tree. .RE .IP The value returned by the \f(CRoutputs\fR function must be an attribute set. The attributes can have arbitrary values; however, various \f(CRnix\fR subcommands require specific attributes to have a specific value (e.g. \f(CRpackages.x86_64-linux\fR must be an attribute set of derivations built for the \f(CRx86_64-linux\fR platform). .IP "\(bu" 3 \f(CRnixConfig\fR: a set of \f(CRnix.conf\fR options to be set when evaluating any part of a flake. In the interests of security, only a small set of set of options is allowed to be set without confirmation so long as \fB\f(CRaccept-flake-config\fR\fR is not enabled in the global configuration: .RS .IP "\(bu" 3 \fB\f(CRbash-prompt\fR\fR .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \fB\f(CRbash-prompt-prefix\fR\fR .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \fB\f(CRbash-prompt-suffix\fR\fR .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \fB\f(CRflake-registry\fR\fR .if n \ .sp -1 .if t \ .sp -0.25v .IP "\(bu" 3 \fB\f(CRcommit-lockfile-summary\fR\fR .RE .SS Flake inputs .LP The attribute \f(CRinputs\fR specifies the dependencies of a flake, as an attrset mapping input names to flake references. For example, the following specifies a dependency on the \f(CRnixpkgs\fR and \f(CRimport-cargo\fR repositories: .LP .EX # A GitHub repository. inputs.import-cargo = { type = \(dqgithub\(dq; owner = \(dqedolstra\(dq; repo = \(dqimport-cargo\(dq; }; # An indirection through the flake registry. inputs.nixpkgs = { type = \(dqindirect\(dq; id = \(dqnixpkgs\(dq; }; .EE .PP Alternatively, you can use the URL-like syntax: .LP .EX inputs.import-cargo.url = \(dqgithub:edolstra/import-cargo\(dq; inputs.nixpkgs.url = \(dqnixpkgs\(dq; .EE .PP Each input is fetched, evaluated and passed to the \f(CRoutputs\fR function as a set of attributes with the same name as the corresponding input. The special input named \f(CRself\fR refers to the outputs and source tree of \fIthis\fR flake. Thus, a typical \f(CRoutputs\fR function looks like this: .LP .EX outputs = { self, nixpkgs, import-cargo }: { ... outputs ... }; .EE .PP It is also possible to omit an input entirely and \fIonly\fR list it as expected function argument to \f(CRoutputs\fR. Thus, .LP .EX outputs = { self, nixpkgs }: ...; .EE .PP without an \f(CRinputs.nixpkgs\fR attribute is equivalent to .LP .EX inputs.nixpkgs = { type = \(dqindirect\(dq; id = \(dqnixpkgs\(dq; }; .EE .PP Repositories that don\(cqt contain a \f(CRflake.nix\fR can also be used as inputs, by setting the input\(cqs \f(CRflake\fR attribute to \f(CRfalse\fR: .LP .EX inputs.grcov = { type = \(dqgithub\(dq; owner = \(dqmozilla\(dq; repo = \(dqgrcov\(dq; flake = false; }; outputs = { self, nixpkgs, grcov }: { packages.x86_64-linux.grcov = stdenv.mkDerivation { src = grcov; ... }; }; .EE .PP Transitive inputs can be overridden from a \f(CRflake.nix\fR file. For example, the following overrides the \f(CRnixpkgs\fR input of the \f(CRnixops\fR input: .LP .EX inputs.nixops.inputs.nixpkgs = { type = \(dqgithub\(dq; owner = \(dqmy-org\(dq; repo = \(dqnixpkgs\(dq; }; .EE .PP It is also possible to \(lqinherit\(rq an input from another input. This is useful to minimize flake dependencies. For example, the following sets the \f(CRnixpkgs\fR input of the top-level flake to be equal to the \f(CRnixpkgs\fR input of the \f(CRdwarffs\fR input of the top-level flake: .LP .EX inputs.nixpkgs.follows = \(dqdwarffs/nixpkgs\(dq; .EE .PP The value of the \f(CRfollows\fR attribute is a \f(CR/\fR-separated sequence of input names denoting the path of inputs to be followed from the root flake. .PP Overrides and \f(CRfollows\fR can be combined, e.g. .LP .EX inputs.nixops.inputs.nixpkgs.follows = \(dqdwarffs/nixpkgs\(dq; .EE .PP sets the \f(CRnixpkgs\fR input of \f(CRnixops\fR to be the same as the \f(CRnixpkgs\fR input of \f(CRdwarffs\fR. It is worth noting, however, that it is generally not useful to eliminate transitive \f(CRnixpkgs\fR flake inputs in this way. Most flakes provide their functionality through Nixpkgs overlays or NixOS modules, which are composed into the top-level flake\(cqs \f(CRnixpkgs\fR input; so their own \f(CRnixpkgs\fR input is usually irrelevant. .SH Lock files .LP Inputs specified in \f(CRflake.nix\fR are typically \(lqunlocked\(rq in the sense that they don\(cqt specify an exact revision. To ensure reproducibility, Nix will automatically generate and use a \fIlock file\fR called \f(CRflake.lock\fR in the flake\(cqs 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 \f(CRflake.nix\fR to locked input specifications. Each node also contains some metadata, such as the dependencies (outgoing edges) of the node. .PP For example, if \f(CRflake.nix\fR has the inputs in the example above, then the resulting lock file might be: .LP .EX { \(dqversion\(dq: 7, \(dqroot\(dq: \(dqn1\(dq, \(dqnodes\(dq: { \(dqn1\(dq: { \(dqinputs\(dq: { \(dqnixpkgs\(dq: \(dqn2\(dq, \(dqimport-cargo\(dq: \(dqn3\(dq, \(dqgrcov\(dq: \(dqn4\(dq } }, \(dqn2\(dq: { \(dqinputs\(dq: {}, \(dqlocked\(dq: { \(dqowner\(dq: \(dqedolstra\(dq, \(dqrepo\(dq: \(dqnixpkgs\(dq, \(dqrev\(dq: \(dq7f8d4b088e2df7fdb6b513bc2d6941f1d422a013\(dq, \(dqtype\(dq: \(dqgithub\(dq, \(dqlastModified\(dq: 1580555482, \(dqnarHash\(dq: \(dqsha256-OnpEWzNxF/AU4KlqBXM2s5PWvfI5/BS6xQrPvkF5tO8=\(dq }, \(dqoriginal\(dq: { \(dqid\(dq: \(dqnixpkgs\(dq, \(dqtype\(dq: \(dqindirect\(dq } }, \(dqn3\(dq: { \(dqinputs\(dq: {}, \(dqlocked\(dq: { \(dqowner\(dq: \(dqedolstra\(dq, \(dqrepo\(dq: \(dqimport-cargo\(dq, \(dqrev\(dq: \(dq8abf7b3a8cbe1c8a885391f826357a74d382a422\(dq, \(dqtype\(dq: \(dqgithub\(dq, \(dqlastModified\(dq: 1567183309, \(dqnarHash\(dq: \(dqsha256-wIXWOpX9rRjK5NDsL6WzuuBJl2R0kUCnlpZUrASykSc=\(dq }, \(dqoriginal\(dq: { \(dqowner\(dq: \(dqedolstra\(dq, \(dqrepo\(dq: \(dqimport-cargo\(dq, \(dqtype\(dq: \(dqgithub\(dq } }, \(dqn4\(dq: { \(dqinputs\(dq: {}, \(dqlocked\(dq: { \(dqowner\(dq: \(dqmozilla\(dq, \(dqrepo\(dq: \(dqgrcov\(dq, \(dqrev\(dq: \(dq989a84bb29e95e392589c4e73c29189fd69a1d4e\(dq, \(dqtype\(dq: \(dqgithub\(dq, \(dqlastModified\(dq: 1580729070, \(dqnarHash\(dq: \(dqsha256-235uMxYlHxJ5y92EXZWAYEsEb6mm+b069GAd+BOIOxI=\(dq }, \(dqoriginal\(dq: { \(dqowner\(dq: \(dqmozilla\(dq, \(dqrepo\(dq: \(dqgrcov\(dq, \(dqtype\(dq: \(dqgithub\(dq }, \(dqflake\(dq: false } } } .EE .PP This graph has 4 nodes: the root flake, and its 3 dependencies. The nodes have arbitrary labels (e.g. \f(CRn1\fR). The label of the root node of the graph is specified by the \f(CRroot\fR attribute. Nodes contain the following fields: .IP "\(bu" 3 \f(CRinputs\fR: The dependencies of this node, as a mapping from input names (e.g. \f(CRnixpkgs\fR) to node labels (e.g. \f(CRn2\fR). .IP "\(bu" 3 \f(CRoriginal\fR: The original input specification from \f(CRflake.lock\fR, as a set of \f(CRbuiltins.fetchTree\fR arguments. .IP "\(bu" 3 \f(CRlocked\fR: The locked input specification, as a set of \f(CRbuiltins.fetchTree\fR arguments. Thus, in the example above, when we build this flake, the input \f(CRnixpkgs\fR is mapped to revision \f(CR7f8d4b088e2df7fdb6b513bc2d6941f1d422a013\fR of the \f(CRedolstra/nixpkgs\fR repository on GitHub. .IP It also includes the attribute \f(CRnarHash\fR, specifying the expected contents of the tree in the Nix store (as computed by \f(CRnix hash-path\fR), and may include input-type-specific attributes such as the \f(CRlastModified\fR or \f(CRrevCount\fR. The main reason for these attributes is to allow flake inputs to be substituted from a binary cache: \f(CRnarHash\fR allows the store path to be computed, while the other attributes are necessary because they provide information not stored in the store path. .IP "\(bu" 3 \f(CRflake\fR: A Boolean denoting whether this is a flake or non-flake dependency. Corresponds to the \f(CRflake\fR attribute in the \f(CRinputs\fR attribute in \f(CRflake.nix\fR. .LP The \f(CRoriginal\fR and \f(CRlocked\fR 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 \f(CRflake.lock\fR will invalidate these. .PP The graph representation of lock files allows circular dependencies between flakes. For example, here are two flakes that reference each other: .LP .EX { 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 = \(dq\(dq; outputs = { self, b }: { foo = 123 + b.bar; xyzzy = 1000; }; } .EE .PP and .LP .EX { inputs.a = ... location of flake A ...; inputs.a.inputs.b.follows = \(dq\(dq; outputs = { self, a }: { bar = 456 + a.xyzzy; }; } .EE .PP 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 \fIdoes\fR use the lock files of dependencies by default.