Template: Terranix Demo
The terranix demo shows how to generate Terraform/OpenTofu configuration directly
from den host definitions. Each host aspect contributes NixOS config and
Terraform resources in a single declaration. The pipeline collects per-host
terranix class modules via policy.instantiate, and terranix’s
flake-module generates all outputs.
How It Works
Section titled “How It Works”den.aspects.* ──┬── nixos → nixosConfigurations.<host> └── terranix → packages.<host> (tofu apply/plan/destroy) devShells.<host> (interactive shell)Two pieces work together:
Pipeline — policy.instantiate collects terranix class modules from each
host’s scope subtree and stores the raw module lists at
flake.terranixModules.<host>:
den.policies.host-to-terranix = { host, ... }: [ (den.lib.policy.instantiate { name = "${host.name}-tf"; class = "terranix"; instantiate = { modules, ... }: modules; intoAttr = [ "terranixModules" host.name ]; })];
den.schema.host.includes = [ den.policies.host-to-terranix ];Terranix flake-module — a perSystem bridge reads the pipeline-collected
modules and feeds them into terranix’s
terranixConfigurations option,
which generates packages, apps (via passthru), and devShells:
perSystem = { pkgs, system, ... }: { terranix.terranixConfigurations = lib.mapAttrs (_: modules: { inherit modules; terraformWrapper.package = pkgs.opentofu; }) (config.flake.terranixModules or {});};Per-host isolation is automatic — applyInstantiates collects only from each
host’s scope subtree, so web-1’s config contains only web-1’s resources.
Project Structure
Section titled “Project Structure”templates/terranix-demo/ flake.nix # inputs: den, terranix, nixpkgs, etc. modules/ den.nix # two hosts (web-1, web-2) with infra fields flake-parts.nix # standard wiring host-schema.nix # extends host schema: server-type, region, image terranix.nix # policy.instantiate + terranix flake-module aspects/ provider.nix # hcloud provider + token variable server.nix # per-host hcloud_server resource hosts/ web-1.nix # web-1 NixOS config (nginx) web-2.nix # web-2 NixOS config (nginx)Host Definitions
Section titled “Host Definitions”Hosts carry infrastructure fields alongside standard den config:
den.hosts.x86_64-linux = { web-1 = { server-type = "cx22"; region = "fsn1"; users.deploy = { }; }; web-2 = { server-type = "cx22"; region = "nbg1"; users.deploy = { }; };};The server-type, region, and image fields are added via a host schema extension:
den.schema.host.imports = [ infraFields ];Shared Aspects
Section titled “Shared Aspects”A provider aspect (included in den.default) declares the Hetzner Cloud
provider for all hosts:
den.aspects.hcloud-provider = { terranix = { terraform.required_providers.hcloud = { source = "hetznercloud/hcloud"; }; provider.hcloud.token = "\${var.hcloud_token}"; };};A parametric server aspect generates a Terraform resource per host. It uses a
host-qualified name so each host produces a uniquely-keyed module:
serverAspect = { host, ... }: { name = "hcloud-server/${host.name}"; terranix = { resource.hcloud_server.${host.name} = { name = host.hostName; server_type = host.server-type; location = host.region; image = host.image; }; };};Flake Outputs
Section titled “Flake Outputs”Terranix’s flake-module generates all outputs automatically:
| Output | Description |
|---|---|
packages.<system>.<host> | Default app (tofu apply) with passthru |
nix run .#<host> | Run tofu apply |
nix run .#<host>.plan | Run tofu plan |
nix run .#<host>.destroy | Run tofu destroy |
nix run .#<host>.init | Run tofu init |
devShells.<system>.<host> | Shell with tofu + all scripts |
nixosConfigurations.<host> | NixOS system configuration |
Try It
Section titled “Try It”# Plan infrastructure for web-1nix run .#web-1.plan
# Applynix run .#web-1
# Destroynix run .#web-1.destroy
# Interactive shell with tofu + scriptsnix develop .#web-1
# Inspect the generated config.tf.jsonnix build .#web-1.config && cat result
# Verify NixOS configs still worknix eval --override-input den . \ ./templates/terranix-demo#nixosConfigurations.web-1.config.services.nginx.enableUsing with Terraform/OpenTofu
Section titled “Using with Terraform/OpenTofu”The apps handle workspace setup and tofu init automatically:
TF_VAR_hcloud_token="your-token" nix run .#web-1.planTF_VAR_hcloud_token="your-token" nix run .#web-1Or use the devShell for interactive work:
nix develop .#web-1export TF_VAR_hcloud_token="your-token"planapplydestroyWhat It Demonstrates
Section titled “What It Demonstrates”| Feature | Shown |
|---|---|
Custom class (terranix) | ✓ |
policy.instantiate for module collection | ✓ |
| Terranix flake-module integration | ✓ |
| Per-host apps (plan/apply/destroy/init) | ✓ |
| Per-host devShells | ✓ |
| Per-host subtree isolation | ✓ |
| Host schema extensions | ✓ |
| Parametric aspects with host-qualified names | ✓ |
| Dual-class aspects (nixos + terranix) | ✓ |
See Also
Section titled “See Also”- Custom Classes — defining new classes
- Policies reference —
policy.instantiate - terranix flake-parts options — terranixConfigurations reference
- terranix.org — terranix documentation