Novice Nix: Flake Templates
Flakes are very handy to setup entirely pure, project-specific
dependencies (not just dependencies, but build steps, shell environments
and more) in a declarative way. Writing Flake expressions can get
repetitive though, oftentimes, you’d much rather start off with a
skeleton. Luckily, nix
already supports templates!
You might already be familiar with nix flake init
, that
drops a “default” flake expression into your current working directory.
If you head over to the manpage:
nix flake init --help
You will read that nix flake init
creates a flake using
the “default template”. Additionally, you can create a flake from a
specific template by passing the -t
flag. Where does this
default originate from?
Flake Registries
Quick detour into registries! Registries are a way to alias popular flakes using identifiers:
# list a few predefined registries
$ nix registry list
. . .
global flake:nixpkgs github:NixOS/nixpkgs
global flake:patchelf github:NixOS/patchelf
global flake:nix-serve github:edolstra/nix-serve
global flake:templates github:NixOS/templates
global flake:nickel github:tweag/nickel
. . .
# you can do
$ nix flake show nickel
# instead of
$ nix flake show github:tweag/nickel
# which is short for
$ nix flake show git+https://github.com/tweag/nickel
You might notice a registry called templates
aliased to
github:NixOS/templates
. Take a peek with
nix flake show
:
$ nix flake show templates
github:NixOS/templates/79f48a7b822f35c068c5e235da2e9fbd154cecee
├───defaultTemplate: template: A very basic flake
└───templates
├───bash-hello: template: An over-engineered Hello World in bash
├───c-hello: template: An over-engineered Hello World in C
├───rust-web-server: template: A Rust web server including a NixOS module
├───simpleContainer: template: A NixOS container running apache-httpd
└───trivial: template: A very basic flake
Aha! There is a flake output called defaultTemplate
.
This is the template being sourced when you run
nix flake init
. Astute readers may conclude the
following:
$ nix flake init
# is equivalent to
$ nix flake init -t templates#defaultTemplate
# is equivalent to
$ nix flake init -t github:NixOS/templates#defaultTemplate
# which is short for
$ nix flake init -t git+https://github.com/NixOS/templates#defaultTemplate
Similarly, the other templates can be accessed via:
$ nix flake init -t templates#c-hello
$ nix flake init -t templates#simpleContainer
# I think you get the drift ...
Rolling your own templates
Alright, so all we need to do is:
- create a flake with a
templates
output - populate our template directories with content
- (optionally) alias our custom templates flake to an identifier using registries, for easier access
Start off by creating a directory to store your templates in (we will be converting this to a registry later):
$ mkdir ~/mytemplates
A flake that exposes a “template” as its output looks something like this:
# inside ~/mytemplates/flake.nix
{
description = "Pepper's flake templates";
outputs = { self, ... }: {
templates = {
latex-report = {
path = ./latex-report-template;
description = "A latex whitepaper project";
};
rust-hello = {
path = ./rust-hello-template;
description = "Simple Hello World in Rust";
};
};
};
}
The path
attribute to each template is what gets copied
over when you initialize a flake. Running
nix flake init -t .#latex-report
will initialize the
current directory with the contents of
./latex-report-template
(we are yet to populate these
directories).
The output of nix flake show
should be something
like:
$ nix flake show
path:/home/np/code/nix-stuff/template-tests?narHash=sha256-{...}
└───templates
├───latex-report: template: A latex whitepaper project
└───rust-hello: template: Simple Hello World in Rust
Populate your template directories with content, here are my template directories for example:
$ tree mytemplates
mytemplates/
├── flake.nix
├── latex-report-template
│ ├── flake.nix
│ ├── makefile
│ └── src
│ ├── meta.sty
│ └── report.tex
└── rust-hello-template
├── Cargo.toml
├── flake.nix
└── src
└── main.rs
And that’s it! Start using your templates with:
$ nix flake init -t ~/mytemplates#rust-hello
$ tree .
.
├── Cargo.toml
├── flake.nix
└── src
└── main.rs
To avoid writing ~/mytemplates
each time, simply alias
it to a registry:
# alias it to `biscuits`
$ nix registry add biscuits ~/mytemplates
# you will see it listed under `user` registries
$ nix registry list
. . .
user flake:biscuits path:/home/np/template-tests
. . .
$ nix flake init -t biscuits#latex-report
Extending the official templates
I personally, would like the biscuits
registry to
include not just my homemade templates, but also the templates from
NixOS/templates
(and maybe a couple of other repositories
in the wild):
{
description = "Pepper's flake templates";
inputs = {
+ official-templates.url = github:NixOS/templates;
+ other-templates.url = github:some-other/templates;
+ };
+
outputs = { self, official-templates, other-templates ... }: {
templates = {
latex-report = {
path = ./latex-report-template;
description = "A latex whitepaper project";
};
rust-hello = {
path = ./rust-hello-template;
description = "Simple Hello World in Rust, with overloaded Rust toolchain";
};
}
+ // official-templates.templates
+ // other-templates.templates;
};
}
Running nix flake show biscuits
will now list templates
from the biscuits
registry as well as the ones from
NixOS/templates
. Ensure that the names don’t collide
though.
I'm Akshay, programmer and pixel-artist. I write open-source stuff. I also design fonts: scientifica, curie.
Reach out at oppili@irc.rizon.net.