Quick summary
Before going deeper, here is the simplest way to think about Azure VNet Terraform.
Why use Terraform for Azure VNet?
Building VNets manually in the Azure portal works for learning, but Terraform is better when you need consistency, peer review, repeatability, and environment standardization.
- It keeps network definitions in code.
- It makes changes reviewable through Git.
- It reduces manual mistakes.
- It makes multi-environment builds easier.
- It fits naturally into CI/CD and platform engineering workflows.
Terraform code
This example creates:
- an Azure resource group
- one Azure Virtual Network
- three subnets inside that VNet
terraform {
required_version = ">= 1.5.0"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.100"
}
}
}
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "network_rg" {
name = var.resource_group_name
location = var.location
}
resource "azurerm_virtual_network" "vnet" {
name = var.vnet_name
location = azurerm_resource_group.network_rg.location
resource_group_name = azurerm_resource_group.network_rg.name
address_space = var.vnet_address_space
tags = {
environment = var.environment
managed_by = "terraform"
purpose = "network-foundation"
}
}
resource "azurerm_subnet" "web" {
name = "web-subnet"
resource_group_name = azurerm_resource_group.network_rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.10.1.0/24"]
}
resource "azurerm_subnet" "app" {
name = "app-subnet"
resource_group_name = azurerm_resource_group.network_rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.10.2.0/24"]
}
resource "azurerm_subnet" "db" {
name = "db-subnet"
resource_group_name = azurerm_resource_group.network_rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.10.3.0/24"]
}
Code breakdown
Terraform block
This defines the Terraform version and AzureRM provider version. Keeping provider versions controlled helps avoid unexpected changes during future runs.
Provider block
The azurerm provider is what Terraform uses to talk to Azure and create resources.
Resource group
Azure resources live inside a resource group, so this is usually one of the first resources created.
Virtual network resource
The azurerm_virtual_network resource creates the VNet itself. The most important part here is the address_space, because this controls the total IP range available to the network.
Subnet resources
Each azurerm_subnet resource creates a subnet inside the VNet. In this example, the web, app, and database layers are separated clearly to support a common three-tier design.
Why this structure is useful
This is a strong beginner-friendly example because it shows that one VNet usually contains multiple subnets with different roles, rather than placing everything into one flat network.
Suggested variables file
A variables file keeps your Terraform code reusable across environments like dev, test, and production.
variable "resource_group_name" {
description = "Name of the Azure resource group"
type = string
}
variable "location" {
description = "Azure region for deployment"
type = string
default = "South Africa North"
}
variable "vnet_name" {
description = "Name of the Azure Virtual Network"
type = string
}
variable "vnet_address_space" {
description = "Address space for the Azure Virtual Network"
type = list(string)
default = ["10.10.0.0/16"]
}
variable "environment" {
description = "Environment name"
type = string
default = "dev"
}
Example terraform.tfvars
resource_group_name = "rg-network-dev-san-1"
location = "South Africa North"
vnet_name = "vnet-app-dev-san-1"
vnet_address_space = ["10.10.0.0/16"]
environment = "dev"
Suggested outputs
Outputs are useful because they expose important values after deployment, which can later be consumed by other modules or pipeline stages.
output "resource_group_name" {
value = azurerm_resource_group.network_rg.name
}
output "vnet_name" {
value = azurerm_virtual_network.vnet.name
}
output "vnet_id" {
value = azurerm_virtual_network.vnet.id
}
output "web_subnet_id" {
value = azurerm_subnet.web.id
}
output "app_subnet_id" {
value = azurerm_subnet.app.id
}
output "db_subnet_id" {
value = azurerm_subnet.db.id
}
How to run it
A simple execution flow looks like this:
terraform init
terraform fmt
terraform validate
terraform plan
terraform apply
In real teams, these steps usually run inside CI/CD after peer review, instead of being executed manually every time.
terraform fmt and terraform validate before planning. It keeps your code clean and catches basic issues early.
Real-world usage
This basic VNet Terraform pattern can grow into real platform designs.
App environment foundation
A team creates one VNet and standard subnets for web, app, database, and management workloads, then hands those subnet IDs to application teams.
Landing zone module
A platform team builds reusable Terraform modules so each business unit or environment can deploy standardized Azure networking with approved naming, tagging, CIDR ranges, and policies.
Hub-and-spoke networking
The same Terraform approach can later expand into separate hub and spoke VNets, peering resources, firewall routes, and private endpoint subnet patterns.
Best practices
- Keep resource names clear and consistent.
- Use variables so the code works across environments.
- Use outputs to expose IDs for later modules.
- Tag resources for ownership, environment, and purpose.
- Plan CIDR ranges carefully before deploying.
- Split networking into modules as the environment grows.
- Keep VNet, subnets, NSGs, and route logic readable instead of over-compressing the code.
- Validate and review Terraform plans before applying.
Common mistakes
- Using overlapping CIDR ranges that break future peering or hybrid connectivity.
- Putting too many unrelated resources into one subnet.
- Hardcoding every value instead of using variables.
- Skipping outputs and making downstream integration harder.
- Using unclear names that become confusing later.
- Mixing too much networking logic into one file before the basics are stable.
Frequently asked questions
What Terraform resource creates an Azure VNet?
The azurerm_virtual_network resource creates an Azure Virtual Network.
Can I create subnets in the same file as the VNet?
Yes. That is a good way to learn. In larger environments, teams often split networking into modules for readability and reuse.
Should I use variables for Azure VNet Terraform?
Yes. Variables make your code reusable across environments and help reduce duplication.
What should I learn after Azure VNet Terraform?
A good sequence is Azure Subnets Terraform, Network Security Groups, Route Tables, NAT, Private Endpoints, and VNet Peering.
Summary
Azure VNet Terraform is one of the best practical starting points for learning Azure infrastructure as code. It teaches you how networking is represented in Terraform, how address space and subnets are declared, and how reusable cloud foundations are built in a real platform workflow.
Official Azure documentation
These are the official Microsoft references that support deeper Azure networking and Terraform-related learning.