TERRANIX(1)
okay bestie, welcome to terranix β pulled straight from the terranix reference pages, and it's genuinely so good πβ¨
πΈ NAME πΈ
terranix β reconfigure a user environment π
β¨ SYNOPSIS β¨
terranix [{ -q | --quiet }] [{ --trace | --show-trace }]
[{ -n | --with-nulls }] [path]
--help
π¦ DESCRIPTION π¦
okay so here's the vibe: Terranix is a NixOS way to generate terraform json. fr fr. You can create modules like you would in NixOS, and honestly that's the whole personality π«Ά
- path β path to the
config.nix. If not given it will use theconfig.nixin the current folder. (default behaviour, love that for you π)
π Run Examples π
To create a JSON file out of a config.nix run:
terranix | jq
To create a JSON file out of a file ./path/my-config.nix run:
terranix ./path/my-config.nix | jq
To create a JSON file and run terraform:
terranix > config.tf.json && terraform init && terraform apply
π§ Example: wrapper driven by _meta.package π§
Sometimes you want your terranix module to declare which Terraform implementation (and plugins) it expects, and then build a small wrapper around the evaluated result. it's giving main character module π
Create a config.nix:
{ pkgs, ... }:
{
_meta.package = pkgs.opentofu.withPlugins (p: [ p.hashicorp_null ]);
terraform.required_providers.null = {
source = "hashicorp/null";
version = ">= 3.0.0";
};
resource.null_resource.hello = {
triggers.message = "hello from terranix";
};
}
Then create a tofu.nix wrapper which uses both the evaluated config and evaluated package:
{ pkgs ? import <nixpkgs> { } }:
let
terranixEval = import <terranix/core/default.nix> {
inherit pkgs;
modules = [ ./config.nix ];
};
configTfJson = (pkgs.formats.json { }).generate "config.tf.json" terranixEval.config;
tofuBin = pkgs.lib.getExe terranixEval._meta.package;
in
pkgs.writeShellApplication {
name = "tofu";
text = ''
ln -sf ${configTfJson} ./config.tf.json
exec ${tofuBin} "$@"
'';
}
Build and run it (no flakes):
nix-build tofu.nix -I terranix=/path/to/terranix
./result/bin/tofu init
./result/bin/tofu apply
lowkey important:_metais removed before JSON rendering, so it never appears inconfig.tf.jsonπβ¨
π OPTIONS π
-q,--quietβ don't print anything except the JSON. that's it. that's the whole job π€«-h,--helpβ print help information. π«Ά--trace,--show-traceβ show trace information if there is an error. super useful when things go sideways ππ₯-n,--with-nullsβ do not strip nulls. nulls will stay. they stay bestie πΈ
π TERRANIX VS HCL π
The nix syntax is similiar to the HCL syntax, but much more powerful. no cap, it's just built different πͺ
In HCL you would do something like this:
resource "aws_instance" "web" {
ami = "${data.aws_ami.ubuntu.id}"
instance_type = "t2.micro"
tags = {
Name = "HelloWorld"
}
}
Which is the equivalent for the following in terranix:
resource."aws_instance"."web" = {
ami = "\${data.aws_ami.ubuntu.id}";
instance_type = "t2.micro";
tags = {
Name = "HelloWorld";
};
}
The same holds for variable, output, data and provider. π¦
πΈ multi line strings πΈ
In terraform you can create multi line strings using the heredoc style:
variable "multiline" {
description = <<EOT
Description for the multi line variable.
The indention here is not wrong.
The terminating word must be on a new line without any indention.
EOT
}
This won't work in terranix. like, at all. nope π In terranix you have to use the nix way of multi line strings:
variable.multiline.description = ''
Description for the multi line variable.
The indention here is not wrong.
All spaces in front of the text block will be removed by terranix.
'';
π escaping expressions π
The form ${expression} is used by terranix and terraform. So, if you want to use a terraform expression in terranix, you have to escape it. There are the two context, multi and single line strings. two whole situations, two whole escapes π
π escaping expressions in single line strings
In single line strings, you escape the via \${expression}. For example :
variable.hcloud_token = {};
provider.hcloud.token = "\${var.hcloud_token}";
π escaping expressions in multi line strings
In multi line strings, you escape via ''${expression}. For example :
resource.local_file.sshConfig = {
filename = "./ssh-config";
content = ''
Host ''${ hcloud_server.terranix_test.ipv4_address }
IdentityFile ./sshkey
'';
};
π MODULES π
The real power behind NixOS and terranix is the module system, which is fundamentally different to the Terraform Module system. Detailed information can be obtained at the NixOS Wiki. π
π Module Structure π
A module always looks like this:
{ config, lib, pkgs, ... }:
{
imports = [
# list of path to other modules.
];
options = {
# attribute set of option declarations.
};
config = {
# attribute set of option definitions.
};
}
π Example Module π
Here is an example module to enable bastion host setups.
{ config, lib, pkgs, ... }:
{
options.security.bastion = {
enable = mkEnableOption "bastion host infrastructure";
vpcID = mkOption {
default = "\${ aws_default_vpc.default.id }";
type = lib.types.str;
description = "vpc id to which the bastion host should proxy";
};
};
config = mkIf (config.security.bastion.enable) {
resource.aws_instance."bastion" = {
ami = "ami-969ab1f6"
instance_type = "t2.micro"
associate_public_ip_address = true
};
resource.aws_security_group."bastion-sg" = {
name = "bastion-security-group";
vpc_id = config.security.bastion.vpcId;
ingress.protocol = "tcp";
ingress.from_port = 22;
ingress.to_port = 22;
ingress.cidr_blocks = ["0.0.0.0/0"];
};
output."bastion_public_ip".value = "\${ aws_instance.bastion.public_ip }";
};
}
Now you can set the following everywhere, to enable the bastion host setup.
{
security.bastion.enable = true;
}
π₯ CONDITIONS AND ASSERTIONS π₯
Conditions and assertions can be used to throw human readable exceptions and to create conditional terraform resources or parameters. yes bestie, error messages that a human can actually read ππ
π§ mkAssert π§
To make an assertion in your module use the mkAssert command. Here is an example:
config = mkAssert (cfg.parameter != "fail") "parameter is set to fail!" {
resource.aws_what_ever."${cfg.parameter}" = {
I = "love nixos";
};
};
β FUNCTIONS β
Nix comes with a ton of functions that make your life easier. A good overview can be found here. π«Ά
π optionalAttrs π
Useful to create a resource depending on a condition. The following example adds a bastion host only if the variable bastionHostEnable is set to true.
This is just an example for illustration, but such things are better solved using modules. (lowkey, listen to the manpage on this one π)
{ lib, ... }:
let
bastionHostEnable = true;
in
{
resource.aws_instance = lib.optionalAttrs bastionHostEnable {
"bastion" = {
ami = "ami-969ab1f6"
instance_type = "t2.micro"
associate_public_ip_address = true
};
};
}
π¦ transform lists to Attributesets π¦
mapβ map a list to another list.zipAttrsβ merge sets of attributes and combine each attribute value into a list.
Useful to create resources out of a small amount of information by containing a lot of similar data. it's the "write once, generate everything" fantasy and it ate π₯
The following example shows how to create 3 s3buckets with the same configuration.
{ lib, ... }:
let
s3Buckets = [
"awesome-com"
"awesome-org"
"awesome-live"
];
in
{
resource.aws_s3_bucket = lib.zipAttrs (lib.map (name:
{
"${name}" = {
bucket = name;
acl = "public-read";
cors_rule = {
allowed_headers = ["*"];
allowed_methods = ["PUT" "POST" "GET"];
allowed_origins = ["https://awesome.com"];
expose_headers = ["ETag"];
max_age_seconds = 3000;
}
};
}
) s3Buckets)
}
π BUGS π
Please report any bugs on the project issue tracker. bestie please, they wanna fix them π«Ά
π SEE ALSO π
terranix-modules(5) β go read it, iykyk β¨
π AUTHOR π
- Ingolf Wagner β Author.
π COPYRIGHT π
Copyright Β© 2019β2022 Ingolf Wagner
and that's the whole page, bestie π
this was terranix, from the terranix reference pages, dated 01/01/1980, filed under TERRANIX(1) β now go terraform apply responsibly, mwah ππ
π¦ where this page comes from
- nixpkgs unstable: terranix 2.9.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms