What Is Terraform?

Terraform (by HashiCorp) uses HashiCorp Configuration Language (HCL) to provision infrastructure declaratively. Its main power comes from multi-provider support — one workflow for Azure, AWS, GCP, Kubernetes, and hundreds more providers. Unlike ARM and Bicep, Terraform maintains a state file that records what it has deployed, enabling it to calculate a precise diff and show you exactly what will change before applying.

OpenTofu is a community-driven, fully open-source fork of Terraform created in 2023 after HashiCorp relicensed Terraform from MPL to BSL — covered in the next module.

Pros

  • Multiple providers — manage Azure, AWS, GCP, and on-premises in one tool
  • Great planning functionality — terraform plan shows an exact diff before any change is made
  • HCL is one of the better notation methods without using a full programming language
  • Module support — reusable modules from the Terraform Registry or your own registry
  • Large ecosystem — thousands of community modules and providers
  • Drift detection — terraform plan compares state vs live resources

Cons

  • State store — requires a shared remote backend (e.g. Azure Blob Storage) for team use; state locking is critical
  • Importing in brown-field environments — terraform import works but mapping existing resources to HCL is tedious
  • Azure day-0 lag — new Azure features may take days or weeks to appear in the azurerm provider; mitigated by the azapi provider (maintained by Microsoft, day-0 coverage)
  • BSL license (Terraform ≥ 1.6) — HashiCorp’s license restricts use in competing products (the reason OpenTofu was forked)

Quick Example

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

provider "azurerm" {
  features {}
}

resource "azurerm_storage_account" "main" {
  name                     = var.storage_account_name
  resource_group_name      = var.resource_group_name
  location                 = var.location
  account_tier             = "Standard"
  account_replication_type = "LRS"
  account_kind             = "StorageV2"
  min_tls_version          = "TLS1_2"
}
terraform init
terraform plan
terraform apply

terraform plan in Depth

terraform plan compares three sources to produce its diff:

  1. Configuration — what your .tf files declare
  2. State file — what Terraform last deployed (.tfstate)
  3. Live infrastructure — the actual current state in Azure (via a refresh)

terraform plan Commands

terraform plan                       # print to console
terraform plan -out=tfplan           # save for later apply
terraform apply tfplan               # apply the saved plan exactly, no re-prompt
terraform plan -target=azurerm_storage_account.main   # scope to one resource

Plan vs What-If

  terraform plan az deployment ... --what-if
Diff source State file + live refresh Azure Resource Manager
Accuracy High — based on provider knowledge Moderate — known noisy diffs
Ordering Shows dependency order No ordering
Saveable Yes (-out=tfplan) No
Apply from saved plan Yes (terraform apply tfplan) No

Azure Providers

There are two Terraform providers for Azure:

Provider Maintained by Day-0 Field names
azurerm HashiCorp No — lag possible Custom HCL-friendly names
azapi Microsoft Yes — same API as ARM/Bicep Mirror ARM/Bicep API names

See the azapi module for details on using both together.

Terraform Registry Terraform Docs Azure Provider Docs


🧪 Lab — One Resource, Many Environments

Your team needs one storage account per environment instead of a single hardcoded one. Convert the resource block below to loop over var.environments with for_each, name each account st${each.key}, and use each.value as its location.

📝 Quiz — Terraform

Next Up

OpenTofu is the open-source fork born from Terraform’s 2023 license change.