Manage macOS with Nix flakes
🚧 This post is under construction. 🚧
A flake is a directory 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).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.
Nix flakes
According to the definition, the structure of a flake is as simple as:
.
├── flake.lock
└── flake.nix
The flake.nix
has these attributes:
description
: what is the flake for?inputs
: an attribute set specifying the dependencies of the flake.outputs
: a function which acceptsself
1 and attributes ofinputs
as its params, and returns the Nix values as its results.
A basic flake.nix
is as simple as the following:
{
description = "A basic flake";
inputs = { };
outputs = { self }: { };
}
Let’s create a flake-example
directory for the flake.nix
, thus, the
flake-example
is called a flake. Run nix build
in the flake for the first
time:
~/flake-example> nix build
error: flake 'path:/Users/james/flake-example' does not provide attribute 'packages.aarch64-darwin.default' or 'defaultPackage.aarch64-darwin'
The error means something is missing in the outputs
, let’s set the result to
self
for a quick experiment:
{
description = "A basic flake";
inputs = { };
outputs = { self }:
let
system = "aarch64-darwin";
in {
packages.${system}.default = self;
};
}
Run nix build
and another error rises:
~/flake-example> nix build
error: flake output attribute 'packages.aarch64-darwin.default' is not a derivation or path
The flake output attribute packages.aarch64-darwin.default
should be a
derivation or path2. Derivation is an important concept in Nix, but to keep
things simple, let’s put it aside and set the output attribute to a Nix path:
{
description = "A basic flake";
inputs = { };
outputs = { self }:
let
system = "aarch64-darwin";
in {
packages.${system}.default = ./.;
};
}
./.
denotes the current directory, similarly, ./flake.nix
denotes the
flake.nix
file in the current directory.
Run nix build
and it is successful:
~/flake-example> tree
.
├── flake.lock
├── flake.nix
└── result -> /nix/store/rl108r5a3nwxyciwj0ibgdi3d55m1rxx-source
The result
symbolic link is the output of the build result, which is located
in the /nix/store
directory.
~/flake-example> tree result
result
├── flake.lock
└── flake.nix
You can see the result
directory has the same files as the flake-example
directory. So our first flake is done, it makes a copy of current directory as
outputs
.