If you’ve been following along with our Infrastructure as Code journey, you’ve seen me mention Terraform quite a bit. This post is your foundation. Whether you’re brand new to Terraform or just want to solidify your understanding, we’re going to walk through the core concepts that everything else builds on.
Why Terraform?
Terraform is a declarative Infrastructure as Code tool. You describe what you want your infrastructure to look like, and Terraform figures out how to create, update, or destroy resources to make it happen.
Key benefits:
- Multi-cloud, multi-platform: Same language and workflow whether you’re deploying to Azure, AWS, Nutanix, VMware, or dozens of other platforms
- Plan before apply: See exactly what will change before you commit
- Drift detection: Know when reality doesn’t match your code
- Massive ecosystem: Thousands of providers and community modules
- State tracking: Terraform knows what it’s managing
Installing Terraform
Grab Terraform from HashiCorp’s downloads page.
terraform -v
HCL Syntax Primer
Everything in Terraform is organized into blocks:
resource "azurerm_resource_group" "rg" {
name = "rg-demo"
location = "eastus"
tags = {
environment = "dev"
managed_by = "terraform"
}
}
resource— the block type"azurerm_resource_group"— the resource type"rg"— your local name for this resource- Everything inside
{}— arguments that configure the resource
Providers
Providers are plugins that let Terraform talk to APIs.
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
}
required_version = ">= 1.3"
}
provider "azurerm" {
features {}
}
Always pin your provider versions.
Resources
Resources are the heart of Terraform. Each resource represents a real infrastructure object.
resource "azurerm_resource_group" "main" {
name = "rg-terraform-basics"
location = "eastus"
}
resource "azurerm_storage_account" "storage" {
name = "tfdemostorage001"
resource_group_name = azurerm_resource_group.main.name
location = azurerm_resource_group.main.location
account_tier = "Standard"
account_replication_type = "LRS"
}
Terraform automatically understands dependencies when you reference one resource from another.
Variables and Outputs
Input Variables
variable "location" {
description = "Azure region for resources"
type = string
default = "eastus"
}
variable "environment" {
description = "Environment name"
type = string
}
Use them in your resources:
resource "azurerm_resource_group" "main" {
name = "rg-${var.environment}"
location = var.location
}
Outputs
output "resource_group_id" {
description = "The ID of the resource group"
value = azurerm_resource_group.main.id
}
State (Local vs Remote)
Terraform tracks the real-world infrastructure in a state file.
Local State
By default, Terraform stores state in terraform.tfstate in your working directory. This works for learning but has problems for teams.
Remote State
For any real work, use a remote backend:
terraform {
backend "azurerm" {
resource_group_name = "rg-terraform-state"
storage_account_name = "tfstateaccount001"
container_name = "tfstate"
key = "dev/terraform.tfstate"
}
}
Benefits:
- Shared state: Everyone sees the same infrastructure
- State locking: Prevents concurrent modifications
- Encryption: Azure Storage encrypts at rest
Workspaces
Workspaces let you manage multiple environments from the same code.
terraform workspace new dev
terraform workspace new prod
terraform workspace select dev
Use the workspace name in your code:
resource "azurerm_resource_group" "main" {
name = "rg-myapp-${terraform.workspace}"
location = var.location
}
The Terraform Workflow
terraform init # Download providers, set up backend
terraform fmt # Auto-format your code
terraform validate # Check for syntax errors
terraform plan # Preview changes
terraform apply # Execute the plan
terraform destroy # Tear down resources
Common Pitfalls & Tips
- Don’t Commit State Files — Add
*.tfstateto.gitignore - Don’t Commit Secrets — Use environment variables or Key Vault
- Start Simple — Don’t try to build a perfectly modularized setup on day one
- Read the Plan — Before every
apply, read the plan carefully
Quick Reference
terraform init # Initialize working directory
terraform fmt # Format code
terraform validate # Validate syntax
terraform plan # Preview changes
terraform apply # Apply changes
terraform destroy # Tear down resources
terraform state list # List resources in state
terraform output # Display outputs