< B / >

Nix Flake

Started Last edited

An entry point for Nix stuff.

§ Writing your first flake

Your flake is the entry point to your application built and run with nix.

Your flake is a function from inputs (which consist of urls for getting package sets) to outputs, with outputs being one big attribute set.

This outputs attribute set looks something like this (very much like a JSON object):

# outputs
{
apps = { ... };
checks = { ... };
devShells = { ... };
formatter = { ... };
legacyPackages = { ... };
nixosConfigurations = { ... };
nixosModules = { ... };
overlays = { ... };
packages = { ... };
}

Every key in here is a special, magic key that Nix interprets in a certain way.

For the minimal (non-functional) flake:

{
inputs = {};
outputs = {...}: {};
}

all of them are empty.

Through populating them, we give our Nix Flake additional capabilities.

The first capability to give our Nix Flakes is normally a development shell.

In Nix Language, we create this like this:

flake.nix
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
};
outputs = { nixpkgs, ... }: {
devShells.x86_64-linux.default = nixpkgs.legacyPackages.x86_64-linux.mkShell {};
};
}

And run it via nix develop (getting it? The devShells output gets run by nix develop):

Terminal window
> nix develop
(nix-shell-env)>

But that doesn’t do anything yet.

For it to do something we need to add something into the devshell:

flake.nix
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
};
outputs = { nixpkgs, ... }: {
devShells.x86_64-linux.default = nixpkgs.legacyPackages.x86_64-linux.mkShell {};
devShells.x86_64-linux.default = nixpkgs.legacyPackages.x86_64-linux.mkShell {
packages = [ nixpkgs.legacyPackages.x86_64-linux.hello ];
};
};
}

(Run nix develop, and then we have the hello executable available.):

Terminal window
> nix develop
(nix-shell-env)> hello
Hello, world!

Let’s clean this up a bit, and then we’re done for now.
There’s lots of repetition in the current file, and the solution to this is not as easy as inserting a let block.

The accepted and easily extensible solution for this is flake-parts, but their homepage is pretty hard to understand at first.

We want to translate our example to this:

flake.nix
{
inputs = {
nixpkgs.url = "https://github.com/nixos/nixpkgs?ref=nixos-unstable";
};
outputs = inputs@{ flake-parts, ... }:
flake-parts.lib.mkFlake { inherit inputs; } {
systems = [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" "x86_64-darwin" ];
perSystem = { pkgs, ... }: {
devShells.default = pkgs.mkShell {
packages = [ pkgs.hello ];
};
};
};
}

This even has the benefit that it will work on all the systems specified.

Draft in Progress

Writing in here is haphazardous, disjointed and sketchy.

It's probably a good idea to come back later.

§ Evaluated Flake top level

You can inspect your flake like this:

Terminal window
nix repl .
> :load-flake . # shorthand ':lf .'
{
_type = "flake";
inputs = { ... };
outputs = { ... };
sourceInfo = { ... };
}

References / Further Reading