Composition of Nix Flakes
Nix flakes allow to include system dependencies from software that are not published on the nix packages repository but that are themselves flakes. This post will explain how to achieve this.
Context
We would like to create a document using the new markup language named typst. Typst presents itself as a markdown like language that produces pdf; moreover, typst promise to be as powerful as latex.
At the time of writing, typst is not yet published on nix package
repository. Fortunately, typst supports nix flake (typst’s source
code contains a flake.nix
file in its root). Consequently, building
typst is as simple as cloning the repository and running nix build .#
in
root of the repository.
Building a project that depends on typst
Starting Point
A good starting point for building a new flake is to use
the below flake.nix
file. This file “builds” the
hello package and exposes a development shell with
deno accessible. The sources are accessible here.
{
description = "Good basic flake template";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
in
{
packages = {
default = pkgs.hello;
};
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [deno];
};
}
);
}
Adding Typst to the Inputs
The first step to use a third-party flake is to add an
input. The input urls format specification is explained
in the “Flake Schema” section of the flakes documentation.
In the typst case, the sources are hosted on github at
https://github.com/typst/typst
which will translate in the
github:typst/typst
url.
{
description = "Basic flake with typst as input";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
typst-pkg.url = "github:typst/typst";
};
outputs = { self, nixpkgs, flake-utils, typst-pkg }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
in
{
packages = {
default = pkgs.hello;
};
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [deno];
};
}
);
}
Using Typst In Development Shell
The second step to use a third party flake is to understand
how to use the inputed flake. Generally, the location of the
“program” exposed in a flake is${input}.packages.${system}.default
.
In our example above, the location is typst-pkg.packages.${system}.default
If it is required to build another target then the default (which is the one
used by nix build .#
), the location ${input}.packages.${system}.${target}
is the one to use.
Finally, using typst in the development shell can be done using
the below flake.nix
.
{
description = "Using typst as 3rd party flake in devshell";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
typst-pkg.url = "github:typst/typst";
};
outputs = { self, nixpkgs, flake-utils, typst-pkg }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
typst = typst-pkg.packages.${system}.default;
in
{
packages = {
default = pkgs.hello;
};
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [deno typst];
};
}
);
}
Bonus: Building a Document With Typts
It would be a shame not to add a script to build the typst document; let’s add it.
From typst’s command line help, it seems that typst compile main.typ main.pdf
will compile the typst source file main.typ
in a pdf located at main.pdf
.
Wrapping typst compile command in a derivation can be done by the
mkDerivation
function as:
pkgs.stdenv.mkDerivation {
name = "document";
src = ./.;
buildInputs = [typst];
buildPhase = "${pkgs.typst}/bin/typst compile main.typ main.pdf";
installPhase = ''
mkdir $out
mv main.pdf $out
'';
}
The final typst/nix flake project can be seen at https://gitlab.com/all-dressed-programming/composition-of-nix-flake with the flake.nix
displayed here.
{
description = "Simple typst application";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
typst-pkg.url = "github:typst/typst";
};
outputs = { self, nixpkgs, flake-utils, typst-pkg }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
typst = typst-pkg.packages.${system}.default;
in
{
packages = {
default = pkgs.stdenv.mkDerivation {
name = "document";
src = ./.;
buildInputs = [typst];
buildPhase = "${pkgs.typst}/bin/typst compile main.typ main.pdf";
installPhase = ''
mkdir $out
mv main.pdf $out
'';
};
};
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [deno typst];
};
}
);
}