Terraform
Terraform
January 12, 2023

Terraform Resource Dependencies Explained

By
Brendan Thompson

Part of the power of Terraform is its ability to have dependencies between resources, and even data sources. These dependencies come in two flavours:

  • Implicit – where a resource may reference another resource/data source
  • Explicit – where an engineer explicitly calls out a dependency between two resources/data sources

With these dependencies in-place it means that resources won’t try and create before something they depend on is available to them. We will go through an example of both implicit and explicit dependencies.

Implicit

In the below example we are creating three separate resources, and they all depend on each other; Resource Group, Virtual Network & Subnet. In our code you can see that we are referencing each in some way. For example our Virtual Network references the Resource Group twice, once for the location and the other for the name of the Resource Group.

Terraform sees this reference and creates a dependency for us in the resource graph between those particular resources.

resource "azurerm_resource_group" "this" {
  name     = "rg-implicit-dependency"
  location = "Australia East"
}

resource "azurerm_virtual_network" "this" {
  name                = "vn-implicit-dependency"
  location            = azurerm_resource_group.this.location
  resource_group_name = azurerm_resource_group.this.name

  address_space = ["10.0.0.0/24"]
}

resource "azurerm_subnet" "this" {
  name                 = "sn-implicit-dependency"
  resource_group_name  = azurerm_resource_group.this.name
  virtual_network_name = azurerm_virtual_network.this.name

  address_prefixes = ["10.0.0.0/28"]
}

The below diagram is the output of the terraform graph command piped into https://github.com/pcasteran/terraform-graph-beautifier. Now you can visually see those references between each resource.

Output of the terraform graph

To prove this lets change the code slightly, instead of using references to resources we will use their values. Our code now looks like below:

resource "azurerm_resource_group" "this" {
  name     = "rg-implicit-dependency"
  location = "Australia East"
}

resource "azurerm_virtual_network" "this" {
  name                = "vn-implicit-dependency"
  location            = "Australia East"
  resource_group_name = "rg-implicit-dependency"

  address_space = ["10.0.0.0/24"]
}

resource "azurerm_subnet" "this" {
  name                 = "sn-implicit-dependency"
  resource_group_name  = "rg-implicit-dependency"
  virtual_network_name = "vn-implicit-dependency"

  address_prefixes = ["10.0.0.0/28"]
}

If we were to run the terraform graph command again we would get a different result entirely! As you can see below we no longer have those dependencies demarcated by arrows in the resource graph.

Resources without dependencies

With this configuration Terraform will try to create all three resources at the same time - this can be limited with the parallelism command line option for apply - which will result in an error!! An example is below which shows that the Virtual Network cannot find the existence of the Resource Group we are referencing.


╷
│ Error: creating/updating Virtual Network: (Name "vn-implicit-dependency" / Resource Group "rg-implicit-dependency"): network.VirtualNetworksClient#CreateOrUpdate: Failure sending request: StatusCode=404 -- Original Error: Code="ResourceGroupNotFound" Message="Resource group 'rg-implicit-dependency' could not be found."
│ 
│   with azurerm_virtual_network.this,
│   on main.tf line 10, in resource "azurerm_virtual_network" "this":
│   10: resource "azurerm_virtual_network" "this" {
│ 

Explicit

Now that we have seen Implicit dependencies in action lets take a look at how Explicit dependencies work. We will use the same example as above, currently it is broken as there are no dependencies in-place, we will fix that with explicit dependencies.


resource "azurerm_resource_group" "this" {
  name     = "rg-explicit-dependency"
  location = "Australia East"
}

resource "azurerm_virtual_network" "this" {
  name                = "vn-explicit-dependency"
  location            = "Australia East"
  resource_group_name = "rg-explicit-dependency"

  address_space = ["10.0.0.0/24"]

  depends_on = [
    azurerm_resource_group.this
  ]
}

resource "azurerm_subnet" "this" {
  name                 = "sn-explicit-dependency"
  resource_group_name  = "rg-explicit-dependency"
  virtual_network_name = "vn-explicit-dependency"

  address_prefixes = ["10.0.0.0/28"]

  depends_on = [
    azurerm_resource_group.this,
    azurerm_virtual_network.this
  ]
}

As you can see we have added a new block inside each resource, this block is called depends_on and it allows us as engineers to call out explicit dependencies between resources or data sources. In our example above instead of using references we are using the explicit name of our Resource Group and Virtual Network, in a real world scenario these might be input variables that are being passed in. Another example of where this might be useful is think of some services you’re building and perhaps they have a business dependency.

The below screenshot shows what our graph will look like when we use the depends_on. (I promise its not copy paste from above)

Closing out

Today we have looked at the two ways we can have dependencies in our Terraform code. Implicit, where we reference a resource or data source within another resource or data source and Explicit where we explicitly tell Terraform about the dependency using the depends_on block. This ensures that all our resources are created in the correct order either due to technical reasons or business! Another reason Terraform is such a powerful Infrastructure-as-Code tool!

Start using the Terraform platform of the future.

A screenshot of the modules page in the Scalr Platform