Azure Networking + Terraform

Build Azure Route Tables with Terraform

Once you understand Azure Route Tables conceptually, the next step is to build them with Terraform. This helps turn routing behavior into reusable infrastructure as code that can be reviewed, versioned, and deployed consistently.

This page shows a practical Azure Route Table Terraform example, explains important blocks like route prefixes and next hop types, and gives you a foundation you can extend later with subnet associations, firewall patterns, hub-and-spoke routing, and hybrid traffic paths.

Quick summary

Before going deeper, here is the simplest way to think about Azure Route Tables Terraform.

What Terraform code that creates an Azure Route Table and one or more custom routes.
Why It makes routing behavior consistent, reviewable, and reusable across environments.
When Use it whenever you want repeatable custom routing through infrastructure as code.
Where It fits into hub-and-spoke networking, firewall patterns, forced tunneling, and hybrid routing workflows.
Who Cloud, DevOps, platform, and network teams usually manage it.
How Using azurerm_route_table and usually azurerm_route.

Why use Terraform for Azure Route Tables?

Route tables can be created manually in the Azure portal, but Terraform is better when you need standardization, reviewable routing logic, repeatable deployments, and consistent multi-environment infrastructure.

  • It keeps routing logic in code instead of clicks.
  • It makes route changes visible in Git and code review.
  • It reduces manual mistakes with prefixes and next hop settings.
  • It helps platform teams deploy consistent routing patterns across environments.
  • It fits naturally into CI/CD and reusable networking modules.
Simple idea: Terraform turns routing behavior into a reusable blueprint instead of a one-time manual portal configuration.

Terraform code

This example creates:

  • an Azure resource group
  • one Azure Route Table
  • two custom routes inside that route table
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_route_table" "app_routes" {
  name                = var.route_table_name
  location            = azurerm_resource_group.network_rg.location
  resource_group_name = azurerm_resource_group.network_rg.name

  tags = {
    environment = var.environment
    managed_by  = "terraform"
    purpose     = "routing-control"
  }
}

resource "azurerm_route" "default_to_firewall" {
  name                   = "default-to-firewall"
  resource_group_name    = azurerm_resource_group.network_rg.name
  route_table_name       = azurerm_route_table.app_routes.name
  address_prefix         = "0.0.0.0/0"
  next_hop_type          = "VirtualAppliance"
  next_hop_in_ip_address = "10.20.0.4"
}

resource "azurerm_route" "onprem_via_gateway" {
  name                = "onprem-via-gateway"
  resource_group_name = azurerm_resource_group.network_rg.name
  route_table_name    = azurerm_route_table.app_routes.name
  address_prefix      = "172.16.0.0/16"
  next_hop_type       = "VirtualNetworkGateway"
}

Code breakdown

Terraform block

This defines the Terraform version and AzureRM provider version. Provider version pinning helps avoid unexpected changes during later deployments.

Provider block

The AzureRM provider is what Terraform uses to communicate with Azure and manage resources.

Resource group

Azure resources need a resource group, so this is usually one of the first resources created.

Route table resource

The azurerm_route_table resource creates the route table container itself. The actual traffic direction behavior comes from the routes placed inside it.

Route resources

The azurerm_route resources define the destination prefix and the next hop Azure should use for matching traffic.

Why separate route resources are useful

Many teams prefer separate route resources because they are easier to review, understand, and maintain than large inline route definitions.

Important route fields in Terraform

A good Azure Route Tables Terraform page should explain that routes are really traffic-matching instructions, not just named entries.

Field What it controls Example
address_prefix The destination range the route should match 0.0.0.0/0, 172.16.0.0/16
next_hop_type Where Azure should send matching traffic next VirtualAppliance, VirtualNetworkGateway, Internet
next_hop_in_ip_address The next hop IP when using a virtual appliance 10.20.0.4
route_table_name The route table that contains the route rt-app-dev-san-1
Important reminder: A route only affects traffic if the destination matches the prefix, and the chosen next hop must make sense for the network design.

Next hop types explained

The next hop type is one of the most important parts of route design because it tells Azure what to do with matching traffic.

Next hop type Meaning Typical use
VirtualAppliance Send traffic to a firewall or network appliance Forced inspection, centralized egress
VirtualNetworkGateway Send traffic toward VPN or ExpressRoute connectivity Hybrid traffic paths
Internet Send traffic toward the internet Custom outbound behavior
VnetLocal Keep traffic inside the virtual network Local Azure traffic behavior
None Drop or black-hole matching traffic Deliberate block of specific paths
Practical reminder: If you choose the wrong next hop type, traffic may follow the wrong path even when the address prefix is correct.

Suggested variables file

Variables make Route Table Terraform code more reusable across development, testing, and production environments.

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 "route_table_name" {
  description = "Name of the Azure Route Table"
  type        = string
}

variable "environment" {
  description = "Environment name"
  type        = string
  default     = "dev"
}

Example terraform.tfvars

resource_group_name = "rg-network-dev-san-1"
location            = "South Africa North"
route_table_name    = "rt-app-dev-san-1"
environment         = "dev"

Suggested outputs

Outputs help expose route table IDs and names so they can be used by subnet association resources or downstream modules.

output "route_table_name" {
  value = azurerm_route_table.app_routes.name
}

output "route_table_id" {
  value = azurerm_route_table.app_routes.id
}

How to run it

A simple Terraform execution flow looks like this:

terraform init
terraform fmt
terraform validate
terraform plan
terraform apply

In real teams, these steps often run through CI/CD after review rather than manually every time.

Good habit: Always run terraform fmt and terraform validate before planning or applying changes.

Real-world usage

This Route Table Terraform pattern can grow naturally into real enterprise routing workflows.

Forced tunneling through firewall

A team uses a default route with next hop type VirtualAppliance so all outbound traffic from a subnet is inspected by a central firewall.

Hybrid routing to on-premises

Traffic destined for datacenter ranges is sent through a virtual network gateway instead of following internet-facing paths.

Hub-and-spoke network design

Spoke subnet route tables direct traffic toward centralized services in the hub for control, logging, or inspection.

Important mindset: Start with a few very clear custom routes. As the environment grows, expand into more structured routing modules and subnet association patterns.

Best practices

  • Use clear route table and route names.
  • Keep destination prefixes specific and intentional.
  • Understand exactly why each next hop is chosen.
  • Document route purpose, not just the route itself.
  • Test route logic in non-production before broad rollout.
  • Be very careful with default routes like 0.0.0.0/0.
  • Keep route design aligned with subnet and security architecture.
  • Separate routing logic from traffic filtering logic in your thinking and code.
Strong next step: After this Route Table example, a natural progression is subnet association, firewall next hop patterns, and broader hub-and-spoke routing design.

Common mistakes

  • Using the wrong address prefix so the route never matches.
  • Choosing the wrong next hop type for the design.
  • Forgetting to associate the route table with the intended subnet.
  • Using default routes too broadly without understanding the impact.
  • Assuming route tables filter traffic like NSGs do.
  • Hardcoding values without variables in reusable environments.
Common beginner trap: Just because Terraform created the route table successfully does not mean traffic will follow the intended path. The design still needs careful validation.

Frequently asked questions

What Terraform resource creates an Azure Route Table?

The azurerm_route_table resource creates an Azure Route Table.

What Terraform resource creates an individual route?

The azurerm_route resource creates an individual custom route inside a route table.

Should I create routes inline or separately?

For small examples either can work, but many teams prefer separate route resources for readability and easier review.

What should I learn after Azure Route Tables Terraform?

A good next step is subnet association, firewall next hop patterns, hub-and-spoke routing, and more advanced forced tunneling designs.

Summary

Azure Route Tables Terraform is one of the best practical ways to understand how Azure traffic direction becomes infrastructure as code. It teaches you how custom routes are expressed, how prefixes and next hops interact, and how reusable routing foundations are built in real Azure environments.

Official Azure documentation

These official references are useful if you want deeper platform details for Azure Route Tables and the Terraform resources used to create them.