Skip to main content

Example — Azure Resource Group

This is a complete walkthrough of authoring the simplest possible useful template: a single Azure Resource Group. The files match the shipped tpl-azure-resource-group verbatim, so you can copy them, change the id, and ship.

By the end of this page you will have a working template that:

  • Provisions one azurerm_resource_group.
  • Lets the user name it.
  • Lets the user pick from a curated list of Azure regions.
  • Surfaces the resource group ID, name, and location as outputs.

1. Directory Layout

In your template repository:

templates/
└── azure/
└── my-resource-group/
├── main.tf
└── template.json

The directory name (my-resource-group) is what users will see in the URL slug. Keep it short and snake-case.


2. main.tf

terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 4.0"
}
}
}

provider "azurerm" {
features {}
subscription_id = var.subscription_id
}

variable "subscription_id" {
description = "Azure Subscription ID"
type = string
}

variable "resource_group_name" {
description = "Name of the resource group"
type = string
}

variable "location" {
description = "Azure region for the resource group"
type = string
default = "West Europe"
}

variable "tags" {
description = "Tags to apply to the resource group"
type = map(string)
default = {}
}

resource "azurerm_resource_group" "main" {
name = var.resource_group_name
location = var.location
tags = var.tags
}

output "resource_group_id" {
value = azurerm_resource_group.main.id
}

output "resource_group_name" {
value = azurerm_resource_group.main.name
}

output "location" {
value = azurerm_resource_group.main.location
}

What is happening, block by block

  • The terraform { required_providers } block pins the Azure provider to ~> 4.0. This locks the major version while allowing minor and patch updates.
  • The provider "azurerm" block configures Azure. The features {} block is required by the provider (even when empty). subscription_id comes from a variable so each deployment can target a different subscription.
  • variable "subscription_id" is auto-injected by Amnify from the project's environment config. It must be declared but does not appear in template.json.
  • variable "tags" is also auto-injected (project + deployment metadata). Declare it; do not duplicate it in template.json.
  • variable "resource_group_name" is the only field the user must fill in.
  • variable "location" is also user-facing, but has a sensible default ("West Europe").
  • The resource block creates the resource group, applying the user's chosen name, location, and Amnify-injected tags.
  • The output blocks expose three values to Amnify after apply. Users see them on the deployment run page.

3. template.json

{
"id": "tpl-azure-my-resource-group",
"name": "Azure Resource Group",
"description": "Create an Azure Resource Group to organize and manage related cloud resources.",
"category": "infrastructure",
"cloud_provider": "azure",
"iac_type": "terraform",
"icon": "FolderOpen",
"variables": [
{
"name": "subscription_id",
"type": "string",
"description": "Azure Subscription ID",
"required": true,
"sensitive": false
},
{
"name": "resource_group_name",
"type": "string",
"description": "Name of the resource group",
"required": true,
"sensitive": false
},
{
"name": "location",
"type": "string",
"description": "Azure region for the resource group",
"default": "West Europe",
"required": true,
"sensitive": false,
"options": [
"West Europe",
"North Europe",
"East US",
"East US 2",
"West US 2",
"Southeast Asia",
"UK South",
"Central US",
"Germany West Central"
]
}
]
}

What is happening, field by field

  • id — change this from tpl-azure-my-resource-group to whatever stable identifier you want. It must be unique within your organization.
  • name — display name on the template card.
  • description — shown beneath the name in the library and on the deployment wizard.
  • category: "infrastructure" — categorizes the template under "Infrastructure" in the library filter.
  • cloud_provider: "azure" — must match the parent directory.
  • iac_type: "terraform" — only supported value today.
  • icon: "FolderOpen" — any Lucide icon name. FolderOpen reads well for a "container" resource.
  • variables — three entries:
    • subscription_id is exposed as a required field so the user picks the subscription. (Some templates omit this and rely entirely on the project's auto-injection — both patterns work.)
    • resource_group_name is a free-text required field.
    • location is a required field with a default and an options array, so it renders as a dropdown of Azure regions.
info

Notice that tags is in main.tf but not in template.json. That is intentional — Amnify auto-injects tags. Adding it to template.json would force users to fill it in by hand for every deployment.


4. Validate Locally

cd templates/azure/my-resource-group
terraform init -backend=false
terraform validate

Expected output:

Success! The configuration is valid.

If validate fails, the most common causes are:

  • A variable name in template.json that is missing in main.tf (or vice versa).
  • A typo in the provider version constraint or resource attribute.
  • Missing features {} block in the azurerm provider.

5. Publish

git add templates/azure/my-resource-group
git commit -m "Add custom Azure Resource Group template"
git push origin main

Then in Amnify:

  1. Navigate to Deploy → Templates.
  2. Click Sync Templates.
  3. Your new template appears in the library within a few seconds, ready for users to deploy.

What This Template Does Not Cover

This is an intentionally minimal example. To explore the full set of features Amnify supports, work through: