A self-contained Nix module that takes inputs (can be from other flakes) and create outputs.
It is comparable to [[https://guix.gnu.org/manual/en/html_node/Channels.html][Guix channels]] (or the NUR) in the way any arbitrary value can be exported, thus extending a Nix module in any direction the author can make it to.
Also, it supercedes Nix channels as a way to manage your system.
- In case you're using [[id:7e8e83d5-4b08-44f6-800d-a322f6960a62][NixOS]], it also provides an easier way to extend it with third-party custom modules.
The flake requires other flakes from the nixpkgs and home-manager as indicated from the URL.
This will get the latest revision of both inputs.
This is not ideal as it will get the latest revisions every time it requests the inputs.
While you can pin the version by adding more information (e.g., =nixpkgs.url = "github:NixOS/nixpkgs/nixos-21.11"=, =home-manager.url = "github:nix-community/home-manager/781d25b315def05cd7ede3765226c54216f0b1fe"=), this isn't really necessary for the most part as we have lockfiles to secure our dependencies version.
These lockfiles can be found at =flake.lock= where complete metadata for the flakes are found.
* Selected list of attributes for outputs
While you can export attributes of any type, there are common attributes you'll mostly see.
As an example, here's the flake of my NixOS configuration.
- =nixosConfigurations.${host}= is a NixOS host configuration.
Each attribute contain a set similar to the traditional set from =/etc/nixos/configuration.nix=.
This is very beneficial for quickly installing only with flakes — e.g., =nixos-install --flake github:foo-dogsquared/nixos-config#zilch= will install with =nixosConfigurations.zilch=.
However, attributes should be created with =lib.nixosSystem= from =nixpkgs= flake.
- =devShells.${system}.${name}= is an attribute set of derivations intended for development shells which are mainly consumed by =nix develop= subcommand.
The subcommand will also set up some things such as the build environment containing the build inputs and environment variables.
You can export it in your flakes through the =templates= attribute.
=templates= is expected to be an attribute set with each attribute representing a template.
By default, we have the =templates= flake from the global registry pointed to [[https://github.com/NixOS/templates][NixOS/templates]] Git repo which can be a starting example.
Take note templates are only static with no templating capabilities whatsoever unlike something like [[id:08f43012-a152-48c4-8943-9fe557a39232][Cookiecutter]].
Flake registries are a convenience feature that allows you to refer to flakes using symbolic identifiers such as =nixpkgs=, rather than full URLs such as =git://github.com/NixOS/nixpkgs=.
#+end_quote
Here's an example of the registry list with some overriden flakes such as the =nixpkgs= flake following from my [[https://github.com/foo-dogsquared/nixos-config][NixOS configuration]].
user flake:custom-nixpkgs path:/home/foo-dogsquared/library/projects/packages/nixpkgs
system flake:config path:/nix/store/azabk9fimqymv1wz4j2lb8jrygffvyfq-source?lastModified=1662173618&narHash=sha256-FrfrZvej2oneAvaLCJ5QB0DsA4ObDxVwyfWEmgmx+kY=
system flake:devshell path:/nix/store/g1y1jdcjb0fvz2dgw1mbkz84d8g8j18v-source?lastModified=1660811669&narHash=sha256-V6lmsaLNFz41myppL0yxglta92ijkSvpZ+XVygAh+bU=&rev=c2feacb46ee69949124c835419861143c4016fb5
system flake:dotfiles path:/nix/store/x0rsi5lvqzzpris4z8sh52r0qin25p6h-source?lastModified=1662114691&narHash=sha256-JvRY4qlXHuo4t7kEPD5DLbCsJqQMNJ2Lfi8Bslt5Q08=&rev=7725082138516476fa48f2b0a827bc62b3699332
system flake:emacs-overlay path:/nix/store/37fzz6za5nqnw20ickl57wp14jb1cnfq-source?lastModified=1662144623&narHash=sha256-LhtXgXW4Ez0fiiDTZcaTbosS8KMiEm6HKJMnTxyIbq8=&rev=8707d84ec67b39d5655929fc974055bcb9a160fb
system flake:flake-utils path:/nix/store/nbkbs33bkw54f60kv5c5y48714l00dpw-source?lastModified=1659877975&narHash=sha256-zllb8aq3YO3h8B%2fU0%2fJ1WBgAL8EX5yWf5pMj3G0NAmc=&rev=c0e246b9b83f637f4681389ecabcb2681b4f3af0
system flake:guix-overlay path:/nix/store/warpn1k8fxl9i90ylzm59qa7479q6ka5-source?lastModified=1662119991&narHash=sha256-tzIblYhiammRfGXoXsyoPUX9iDDqYMnz1b0lJY9DloA=
system flake:helix-editor path:/nix/store/3vik1l2ihdkx6d0jg390b41app4g0ika-source?lastModified=1662159247&narHash=sha256-D+UirTzF4gqOnSyPpd9MOrQyRV9iaK4ktY514HtlhPo=&rev=e917a8e0be29aa3f8aaa537e0aa88e6df8ce974e
system flake:home-manager path:/nix/store/3ngcv9lamdaqsxw0bixnc3zjwbr6068z-source?lastModified=1661824092&narHash=sha256-nSWLWytlXbeLrx5A+r5Pso7CvVrX5EgmIIXW%2fEXvPHQ=&rev=5bd66dc6cd967033489c69d486402b75d338eeb6
system flake:neovim-nightly-overlay path:/nix/store/awbf898silibkrdrslj5wg4al85873df-source?lastModified=1662106618&narHash=sha256-fawP7iB5o3ZD%2fVFcfv8gsB6lzGzxR1bfURikuVCpsMM=&rev=d3262c72f00252e00fc93ad2021f446450cc735e
system flake:nix-alien path:/nix/store/xx9hqbq4pzcg97syqfql86g2nbh1llax-source?lastModified=1657876248&narHash=sha256-UkcXnWq9ukTFgLhxafg3cnQZmWL%2fjNgLbJbE1Geo4k4=&rev=897f10267138748956b7720c5a82bba8a90a832e
system flake:nix-colors path:/nix/store/07zfr4blpnyxn697byahlb7znz8rm9xm-source?lastModified=1661006226&narHash=sha256-OytVjY%2fW1ASw+N+xrCRaKhcs76ZIcrVRf9xXhOnWzno=&rev=861546e123ef13c480338edbad8c6f2e7baf0777
system flake:nix-ld path:/nix/store/53hfjz1qjg0k7w29z0c57lxjmqkimpsv-source?lastModified=1652641841&narHash=sha256-TTBz20XR2vmvOSDu8hXcbHbOEI0t%2fIWq8vZuRKyep1E=&rev=c25cc4b5ec65f03c2bb96f927ae724a59c51d7ee
system flake:nixos-generators path:/nix/store/dawikzqa2bhnp5pqf0yiy3jiw6c8jhj0-source?lastModified=1660727616&narHash=sha256-zYTIvdPMYMx%2fEYqXODAwIIU30RiEHqNHdgarIHuEYZc=&rev=adccd191a0e83039d537e021f19495b7bad546a1
system flake:nixpkgs path:/nix/store/8x9s4zv7dzmwxmm8lhsxk3nf8lxlh52q-source?lastModified=1662019588&narHash=sha256-oPEjHKGGVbBXqwwL+UjsveJzghWiWV0n9ogo1X6l4cw=&rev=2da64a81275b68fdad38af669afeda43d401e94b
system flake:nur path:/nix/store/f6d0qa1pn9cljmc8xxa0bply4im4b7jj-source?lastModified=1662170849&narHash=sha256-bIY4zURNsvaUK2eVoMz02lBDZPLwXP2KzinNvEWtlsw=&rev=258028926ec1a0976a6f9ec1c106e7cc1345f0c0
system flake:rust-overlay path:/nix/store/8pzvk34qgr1nm150g328gcd4qzrnx8vq-source?lastModified=1662173844&narHash=sha256-+ZgW98Y8fZkgFSylE+Mzalumw+kw3SVivZznbJqQaj8=&rev=8ac6d40380dc4ec86f1ff591d5c14c8ae1d77a18
system flake:sops-nix path:/nix/store/8vk2k07z2kr8r9hhls0fgv828na4fpr7-source?lastModified=1661660105&narHash=sha256-3ITdkYwsNDh2DRqi7FZOJ92ui92NmcO6Nhj49u+JjWY=&rev=d92fba1bfc9f64e4ccb533701ddd8590c0d8c74a
- It is managed through =nix registry= subcommand or set =nix.registry= in your system configuration.
- Registries are primarily written as JSON files in certain files (e.g., =$XDG_CONFIG_HOME/nix/registry=, =/etc/nix/registry.json=).
For more information, see the [[https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-registry.html#registry-format][registry format from the manual]].
Unlike the traditional Nix channels, the inclusion of arbitrary files and their locations doesn't seem to affect the reproducibility since it is mostly used as a convenience feature after all.
- The flakes from default registry are mostly getting the latest revisions of the flake per invocation so it is best practice to pin them (e.g., =nix registry pin=, through =nix.registry= while setting the NixOS systems in =flake.nix=).
- There are primarily three registries to worry about: user, system, and global.
This is also the reason it downloads something why each time you invoke a Nix-related command (e.g., =nix search=, =nix edit=). [fn:: Pinning the flakes from the global registry will simply resolve this issue.]
If you're using Nix flakes for your NixOS configuration, it is recommended to set the =nixpkgs= registry item to the nixpkgs input (e.g., ~nix.registry.nixpkgs.url = nixpkgs;~).
* Flake lockfile
:PROPERTIES:
:ID: 6f261080-77da-4d75-9426-7ca6f285371c
:END:
It is unreproducible to make our inputs to only set like the following list.
#+name: itm:flake-inputs-urls
- github:NixOS/nixpkgs/nixos-unstable
- github:foo-dogsquared/nix-overlay-guix
- github:nix-community/NUR
- git+file:///home/user/projects/NUR
That's because Nix resolves the previous list of inputs to their latest revisions each time Nix refers to the input.
You could see this effect by making use of Nix commands that takes a flake as an input.
Let's take the most common and frustrating use case that many will encounter.
#+begin_src shell :eval no
nix search nixpkgs hello
#+end_src
Assuming =nixpkgs= from the flake registry points to =github:NixOS/nixpkgs= (which you can just replace =nixpkgs= with the URL, if you've pinned it already), this will resolve to the latest revision from the given URL.
If you're using the above command often, you'll know this will run slow since you're fetching and evaluating a new version of the whole nixpkgs repo each time.
To mitigate, we could accurately describe the inputs by including the revision hash.
Fortunately, *Nix already does this by capturing the resolved versions and dependencies of a list of inputs ([[list:flake-inputs-urls][this list of flake inputs]] as an example) and storing them in a file*.
The file is specifically referred to as a lockfile.
This is usually stored in a file called =flake.lock= alongside your flake definition file (i.e., =flake.nix=).
With the lockfile present, Nix will now use the captured versions from the lockfile as the inputs defined in =flake.nix=.
- =nix flake update= will resolve the inputs from the flake definition and capture the updated versions to the lockfile.
One of the nicer features with the [[lst:nix-version][current experimental version]] of the Nix CLI is =--commit-lock-file= which creates a commit with a formatted message of updated inputs. [fn:: You can also change the commit summary with =--commit-lockfile-summary= option.]
- =nix flake lock= will store missing inputs in the lockfile.
This command also has fine-grained control in controlling the lockfile in some ways.
For example, you can update a specific input =a= with =nix flake --update-input a=.
** Lockfile format
The flake lockfile format can vary especially that it has different versions.
But for the most part, exploring a lockfile is pretty similar as a lockfile is simply a JSON file containing metadata regarding the flake inputs.
For example, this is the whole flake lockfile of this notebook which is a simple flake intended to deliver the environment needed for this notebook including a bunch of language interpreters and programs for [[id:5569a49f-c387-4da2-8f68-d8452e35ee5b][Org mode: Babel]].
#+caption: This notebook's flake lockfile as of 2022-09-04