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://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.