skills/.curated/arm-to-terraform-migration/SKILL.md
Convert Azure ARM templates to Terraform HCL configuration with full resource mapping and dependency preservation
npx skillsauth add guicedee/ai-rules arm-to-terraform-migrationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
You are an ARM template to Terraform migration expert. When this skill is invoked, you help users convert Azure Resource Manager (ARM) templates into equivalent Terraform configurations while preserving resource relationships, dependencies, and outputs.
When a user requests ARM to Terraform migration:
Parse ARM Template:
template.jsonparameters.jsondependsOnMap Resources to Terraform:
Convert Expressions:
[parameters('name')] → Terraform: var.name[variables('name')] → Terraform: local.name[concat(...)] → Terraform: String interpolation[reference(...)] → Terraform: Resource attributesGenerate Terraform Files:
main.tf: Resource definitionsvariables.tf: Converted parametersoutputs.tf: Converted outputsterraform.tf: Provider configuration| ARM Resource Type | Terraform Resource |
|------------------|-------------------|
| Microsoft.Resources/resourceGroups | azurerm_resource_group |
| Microsoft.Storage/storageAccounts | azurerm_storage_account |
| Microsoft.Network/virtualNetworks | azurerm_virtual_network |
| Microsoft.Network/networkInterfaces | azurerm_network_interface |
| Microsoft.Network/publicIPAddresses | azurerm_public_ip |
| Microsoft.Network/networkSecurityGroups | azurerm_network_security_group |
| Microsoft.Compute/virtualMachines | azurerm_linux_virtual_machine or azurerm_windows_virtual_machine |
| Microsoft.Web/sites | azurerm_app_service or azurerm_linux_web_app |
| Microsoft.Web/serverfarms | azurerm_service_plan |
| Microsoft.Sql/servers | azurerm_mssql_server |
| Microsoft.Sql/servers/databases | azurerm_mssql_database |
| Microsoft.KeyVault/vaults | azurerm_key_vault |
| Microsoft.ContainerService/managedClusters | azurerm_kubernetes_cluster |
ARM nested resources become separate Terraform resources with references:
ARM:
{
"type": "Microsoft.Sql/servers",
"resources": [{
"type": "databases",
"name": "mydb"
}]
}
Terraform:
resource "azurerm_mssql_server" "main" {
# ...
}
resource "azurerm_mssql_database" "main" {
server_id = azurerm_mssql_server.main.id
# ...
}
ARM parameters.json:
{
"parameters": {
"location": {
"value": "eastus"
},
"vmSize": {
"value": "Standard_D2s_v3"
}
}
}
Terraform variables.tf:
variable "location" {
description = "Azure region"
type = string
default = "eastus"
}
variable "vm_size" {
description = "VM size"
type = string
default = "Standard_D2s_v3"
}
| ARM Function | Terraform Equivalent |
|-------------|---------------------|
| [concat('a', 'b')] | "${a}${b}" or "a${b}" |
| [format('{0}-{1}', 'a', 'b')] | "${a}-${b}" |
| [parameters('name')] | var.name |
| [variables('name')] | local.name |
| [resourceId(...)] | resource.name.id |
| [reference('name')] | resource.name (attribute) |
| [uniqueString(...)] | random_string.name.result |
| [resourceGroup().location] | var.location or data.azurerm_resource_group.main.location |
ARM:
{
"type": "Microsoft.Network/networkInterfaces",
"dependsOn": [
"[resourceId('Microsoft.Network/virtualNetworks', 'myVNet')]"
]
}
Terraform (implicit dependency):
resource "azurerm_network_interface" "main" {
subnet_id = azurerm_subnet.main.id # Implicit dependency
}
Terraform (explicit dependency):
resource "azurerm_network_interface" "main" {
depends_on = [azurerm_virtual_network.main]
}
Read and understand:
For each ARM resource:
variables.tf with all parametersmain.tf with all resourcesterraform.tf with azurerm provider{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"parameters": {
"location": {
"type": "string",
"defaultValue": "eastus"
},
"storageAccountName": {
"type": "string"
}
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2021-04-01",
"name": "[parameters('storageAccountName')]",
"location": "[parameters('location')]",
"sku": {
"name": "Standard_LRS"
},
"kind": "StorageV2"
}
],
"outputs": {
"storageAccountId": {
"type": "string",
"value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
}
}
}
variables.tf:
variable "location" {
description = "Azure region"
type = string
default = "eastus"
}
variable "storage_account_name" {
description = "Storage account name"
type = string
validation {
condition = length(var.storage_account_name) >= 3 && length(var.storage_account_name) <= 24
error_message = "Storage account name must be between 3 and 24 characters."
}
}
main.tf:
resource "azurerm_storage_account" "main" {
name = var.storage_account_name
resource_group_name = azurerm_resource_group.main.name
location = var.location
account_tier = "Standard"
account_replication_type = "LRS"
account_kind = "StorageV2"
}
outputs.tf:
output "storage_account_id" {
description = "ID of the storage account"
value = azurerm_storage_account.main.id
}
terraform.tf:
terraform {
required_version = ">= 1.6"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
}
}
provider "azurerm" {
features {}
}
If scripts/migrate-arm.js exists, use it:
node scripts/migrate-arm.js \
--template template.json \
--parameters parameters.json \
--output ./terraform
The script will:
terraform import for existing resourcesARM:
{
"copy": {
"name": "vmCopy",
"count": 3
}
}
Terraform:
resource "azurerm_linux_virtual_machine" "main" {
count = 3
name = "vm-${count.index}"
# ...
}
ARM:
{
"condition": "[equals(parameters('env'), 'prod')]"
}
Terraform:
resource "azurerm_..." "main" {
count = var.environment == "prod" ? 1 : 0
# ...
}
See references/arm-terraform-mapping.md for complete resource type mappings.
development
Install Codex skills into $CODEX_HOME/skills from a curated list or a GitHub repo path. Use when a user asks to list installable skills, install a curated skill, or install a skill from another repo (including private repos).
tools
Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Codex's capabilities with specialized knowledge, workflows, or tool integrations.
development
WebAwesome icon integration for JWebMP — modern, open-source icon library. Provides 1,500+ icons with solid/regular styles, sizing, rotation, animation, and CSS utilities. Drop-in FontAwesome alternative with fresh designs. Use when working with WebAwesome icons, modern icon designs, or as FontAwesome alternative in JWebMP applications.
development
WebAwesome Pro integration for JWebMP with premium icons and features. Extends jwebmp-webawesome with additional styles, premium icons, and advanced features. Use when working with WebAwesome Pro icons or premium WebAwesome features in JWebMP applications.