template.json:
list(object)withmin_items- Nested
objectinside alist(object) - Deeply nested
list(object)(subnet → NACL → ingress/egress rules) optionsenums for protocol and action choicesoptional(...)Terraform syntax for non-required nested fields
tpl-aws-vpc verbatim. Treat this as the canonical reference for advanced authoring.
The VPC template provisions:
- One
aws_vpc. - One or more
aws_subnet(the user defines them; at least one is required). - An optional internet gateway (one of the subnets opts in via
create_igw). - An optional NAT gateway (one of the subnets opts in via
create_nat_gateway). - Optional Network ACLs per subnet, with custom ingress/egress rules.
- Optional route tables per subnet.
1. Directory Layout
2. main.tf
The full file is long. It is broken down here into the patterns that matter for template authoring; the complete source is in the shipped template.
Provider and required-providers
Top-level variables
The deeply-nested subnets variable
The interesting one. subnets is a list(object) where each element has an optional NACL object (which itself contains lists of rules) and an optional route table.
optional(bool, false)andoptional(string, "")make a nested field optional with a default. The user can omit them in the UI; Terraform treats them asfalse/"".optional(object({...}))with no default makes the entire nested object optional — when omitted, the value isnulland you checkif s.nacl != nullin yourlocals.validationat the bottom enforcesmin_itemsat plan time. The same constraint is also expressed intemplate.jsonso it surfaces in the UI before plan runs.
Resources, locals, outputs
These are standard Terraform — see the full source for the resource declarations. The key idea: rich nested input → flat resources viafor_each and flatten over locals.
3. template.json
This is where the advanced manifest features earn their keep. The full file ships at aws/vpc/template.json. Walk through it section by section.
Top-level
region with options
User-facing region selector with a curated dropdown.
subnets — list(object) with min_items
The outer shape. Note min_items: 1 enforces “at least one subnet” in the UI.
Subnet fields — primitives
Inside theschema:
Subnet nacl — nested object with deeply nested list(object)
The NACL is itself an object (required: false), which in turn contains two list(object) fields. Each rule has primitives and option-driven enums:
Subnet route_table — optional object
A note on conditional requirements
Thetarget_id field above is conceptually required only for some target_type values (vpc_peering, transit_gateway, network_interface) but optional for others (internet_gateway, nat_gateway, where Amnify auto-resolves the ID).
Amnify’s condition field on a variable can hide or show a field based on a sibling’s value, but it does not currently support multi-value conditions (“show when target_type is one of [a, b, c]”). The pattern used by the shipped template is:
- Mark
target_idasrequired: falseintemplate.json. - Document the per-
target_typerequirement in thedescription. - Enforce the rule at plan time with a Terraform
validationblock.
4. Validate Locally
terraform plan against a hand-crafted terraform.tfvars.json to make sure the variable shape lines up. Example:
validate is enough to catch type mismatches.)
5. Publish
Lessons From This Template
If you take only three things from this example, take these:- Mirror the
.tfandtemplate.jsonshapes exactly. Every nestedoptional(object({...}))in Terraform corresponds to anobjectwithrequired: falsein JSON. Everylist(object({...}))corresponds tolist(object)with aschemaarray. - Use
optionsfor enums. Anywhere your Terraform takes one of a known set of strings, expose it asoptions. The UI dropdown prevents typos and the user does not need to memorize the valid values. - Combine manifest validation with Terraform
validation. The manifest catches structural issues (missing required field, empty list); Terraformvalidationblocks catch semantic issues (cross-field rules). Use both.
Next Steps
- template.json Reference — for any field this example didn’t exercise (e.g.
condition,resource_type). - Variable Types & Secrets — for
sensitivevariables, which the VPC template doesn’t use.