Home / Posts / Novice Nix: Flake Templates View Raw
05/10 — 2021
91.51 cm   5.5 min

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.

Hi.

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.

Home / Posts / Novice Nix: Flake Templates View Raw