Answers: <p><strong>Update: As of TF 0.13x, <code>depends_on</code> is supported to create dependencies between modules. Using <code>depends_on</code> should be preferable over using the method detailed below.</strong></p>
  <p>The previous most popular answer is out of date with Terraform 0.12.24.</p>
  <p><code>depends_on</code> is a protected variable, and cannot be used in a <code>module</code>.
  In addition there are a few syntax differences.</p>
  <p>I've updated the example below.</p>
  <pre><code># ROOT level main.tf
  # -------------------------------------------------------------------
  # Create NAT Gateway - Associates EIP as well
  # -------------------------------------------------------------------
  module &quot;vpc_nat_gateway&quot; {
    source            = &quot;./vpc_nat_gateway&quot;
    vpc_id            = module.vpc.id
    public_subnet_ids = module.vpc_subnets.public_subnet_ids
    private_cidr      = var.private_cidr
    common_tags       = local.common_tags
  }
  
  # -------------------------------------------------------------------
  # Create Private Routes
  # -------------------------------------------------------------------
  module &quot;vpc_private_route&quot; {
    source         = &quot;./vpc_private_route&quot;
    vpc_id.        = module.vpc.id
    nat_gateway_id = module.vpc_nat_gateway.nat_gateway_id
    common_tags    = local.common_tags
  
    # Depends is a custom variable, depends_on is a reserved keyword.
    depends = [module.vpc_nat_gateway.nat_gateway_id]
  }
  </code></pre>
  <pre><code># vpc_private_route module - main.tf
  variable &quot;depends&quot; {
    default = []
  }
  
  resource &quot;null_resource&quot; &quot;depends_on&quot; {
    triggers = {
      depends_on = &quot;${join(&quot;&quot;, var.depends)}&quot;
    }
  }
  
  data &quot;aws_nat_gateway&quot; &quot;az1&quot; {
    vpc_id = var.vpc_id
  
    depends_on = [
      null_resource.depends_on
    ]
  }
  
  data &quot;aws_nat_gateway&quot; &quot;az2&quot; {
    vpc_id = var.vpc_id
  
    depends_on = [
      null_resource.depends_on
    ]
  }
  </code></pre>
  
Answers: CC BY-SA 4.0
Answers: 2020-04-08T17:16:42.510Z
Answers: 2022-05-13T21:42:19.407Z
Answers: 2022-05-13T21:42:19.407Z
Answers: MrPooh
Answers: <p>These are hacks (understandably as you couldn't explicitly do this in Terraform &lt; 0.13).</p>
  <p>Now however, with 0.13, we have <code>depends_on</code> for modules: <a href="https://github.com/hashicorp/terraform/blob/v0.13/CHANGELOG.md#0130-august-10-2020" rel="noreferrer">https://github.com/hashicorp/terraform/blob/v0.13/CHANGELOG.md#0130-august-10-2020</a></p>
  
Answers: CC BY-SA 4.0
Answers: 2020-11-27T08:17:37.523Z
Answers: 2020-11-27T08:17:37.523Z
Answers: Snowcrash
Answers: <p>There is a hacky workaround for getting Terraform to do module dependencies. You can force the module to be aware of the Terraform calling it like this:</p>
  
  <pre><code># ROOT level main.tf
  # -------------------------------------------------------------------
  # Create NAT Gateway - Associates EIP as well
  # -------------------------------------------------------------------
  module "vpc_nat_gateway" {
    source            = "./vpc_nat_gateway"
    vpc_id            = "${ module.vpc.id }"
    public_subnet_ids = "${ module.vpc_subnets.public_subnet_ids }"
    private_cidr      = "${ var.private_cidr }"
    common_tags       = "${ local.common_tags }"
  }
  
  # -------------------------------------------------------------------
  # Create Private Routes
  # -------------------------------------------------------------------
  module "vpc_private_route" {
    source         = "./vpc_private_route"
    vpc_id.        = "${ module.vpc.id }"
    nat_gateway_id = "${ module.vpc_nat_gateway.nat_gateway_id }"
    common_tags    = "${ local.common_tags }"
  
    depends_on = ["${module.vpc_nat_gateway.nat_gateway_id}"]
  }
  </code></pre>
  
  <pre><code># vpc_private_route module - main.tf
  variable "depends_on" {
    default = []
  }
  
  resource "null_resource" "depends_on" {
    triggers {
      depends_on = "${join("", var.depends_on)}"
    }
  }
  
  data "aws_nat_gateway" "az1" {
    vpc_id = "${ var.vpc_id }"
  
    tags {
      Name = "*NAT GW AZ 1"
    }
  
    depends_on = [
      "null_resource.depends_on"
    ]
  }
  
  data "aws_nat_gateway" "az2" {
    vpc_id = "${ var.vpc_id }"
  
    tags {
      Name = "*NAT GW AZ 2"
    }
  
    depends_on = [
      "null_resource.depends_on"
    ]
  }
  </code></pre>
  
  <p>It adds a lot of boilerplate but you will get the desired effect.</p>
  
Answers: CC BY-SA 4.0
Answers: 2019-02-02T02:17:43.250Z
Answers: Thank you @Briansbum for this input and excellent example. I will try this my next day in office and report back.
Answers: Steven K7FAQ
Answers: CC BY-SA 4.0
Answers: 2019-02-01T08:49:57.990Z
Answers: 2019-02-01T08:49:57.990Z
Answers: Briansbum
Answers: <p>I've not tried this, but you could have a null_resource with a local-exec running a sleep command and make your resource dependent on that resource with a depends_on lifecycle argument.</p>
  
Answers: CC BY-SA 4.0
Answers: 2024-05-09T13:33:11.223Z
Answers: 2024-05-09T13:33:11.223Z
Answers: Aaron Brockmeyer
Body: <p>Today I am working on building out several custom Terraform Modules. The issue that I am trying to figure out how to work around dependencies within modules. Until TF 0.12 is released we cannot declare a module to be dependent upon another module. So, in this root level main.tf:</p>
  
  <pre><code># ROOT level main.tf
  # -------------------------------------------------------------------
  # Create NAT Gateway - Associates EIP as well
  # -------------------------------------------------------------------
  module "vpc_nat_gateway" {
    source            = "./vpc_nat_gateway"
    vpc_id            = "${ module.vpc.id }"
    public_subnet_ids = "${ module.vpc_subnets.public_subnet_ids }"
    private_cidr      = "${ var.private_cidr }"
    common_tags       = "${ local.common_tags }"
  }
  
  # -------------------------------------------------------------------
  # Create Private Routes
  # -------------------------------------------------------------------
  module "vpc_private_route" {
    source         = "./vpc_private_route"
    vpc_id.        = "${ module.vpc.id }"
    nat_gateway_id = "${ module.vpc_nat_gateway.nat_gateway_id }"
    common_tags    = "${ local.common_tags }"
  }
  
  # vpc_private_route module - main.tf
  data "aws_nat_gateway" "az1" {
    vpc_id = "${ var.vpc_id }"
  
    tags {
      Name = "*NAT GW AZ 1"
    }
  }
  
  data "aws_nat_gateway" "az2" {
    vpc_id = "${ var.vpc_id }"
  
    tags {
      Name = "*NAT GW AZ 2"
    }
  }
  </code></pre>
  
  <p>The result output is:</p>
  
  <pre><code>------ SNIP -----
  module.vpc_nat_gateway.aws_nat_gateway.nat[1]: Creation complete after 1m50s (ID: nat-02a7f4279cec3a6c8)
  module.vpc_nat_gateway.aws_nat_gateway.nat.0: Still creating... (2m0s elapsed)
  module.vpc_nat_gateway.aws_nat_gateway.nat[0]: Creation complete after 2m0s (ID: nat-0695a12d9c0305e4c)
  
      Error: Error applying plan:
  
      3 error(s) occurred:
  
      * module.vpc_private_route.data.aws_subnet_ids.private: data.aws_subnet_ids.private: no matching subnet found for vpc with id vpc-0b530d1885e74067b
      * module.vpc_private_route.data.aws_nat_gateway.az2: data.aws_nat_gateway.az2: no matching NAT gateway found: {
      Filter: [{
          Name: "vpc-id",
          Values: ["vpc-0b530d1885e74067b"]
          },{
          Name: "tag:Name",
          Values: ["*NAT GW AZ 2"]
          }]
      }
      * module.vpc_private_route.data.aws_nat_gateway.az1: data.aws_nat_gateway.az1: no matching NAT gateway found: {
      Filter: [{
          Name: "vpc-id",
          Values: ["vpc-0b530d1885e74067b"]
          },{
          Name: "tag:Name",
          Values: ["*NAT GW AZ 1"]
          }]
      }
  </code></pre>
  
  <p>As observed in the output the Nat Gateways are created. <code>Terraform show</code> output tells us the Filters are correct:</p>
  
  <pre><code>    module.vpc_nat_gateway.aws_nat_gateway.nat.0:
          id = nat-0695a12d9c0305e4c
          allocation_id = eipalloc-023ca087ad4fb830e
          network_interface_id = eni-015e39fc8d3bc0de3
          private_ip = 172.16.254.16
          public_ip = 18.215.5.116
          subnet_id = subnet-0f2c039e8fd804f30
          tags.% = 7
          tags.Environment = development
          tags.Infrastructure = No
          tags.Name = **redacted** NAT GW AZ 1
      module.vpc_nat_gateway.aws_nat_gateway.nat.1:
          id = nat-02a7f4279cec3a6c8
          allocation_id = eipalloc-0a95264c2eef26673
          network_interface_id = eni-03bddcca2fbeeff44
          private_ip = 172.16.254.84
          public_ip = 3.91.167.246
          subnet_id = subnet-08ee61f3aa43acbe9
          tags.% = 7
          tags.Environment = development
          tags.Infrastructure = No
          tags.Name = **redacted** NAT GW AZ 2
  </code></pre>
  
  <p>Executing a subsequent <code>terraform apply</code> runs without any errors.</p>
  
  <pre><code># Yes, the IDs are different in this example than from above.
  # ---- SNIP ----
      module.vpc_private_route.data.aws_nat_gateway.az1:
          id = nat-0c127e538a26b2bd5
          allocation_id = eipalloc-01775b8e88502d4b9
          network_interface_id = eni-0b0bd2203bd3f5873
          private_ip = 172.16.254.45
          public_ip = 3.83.199.207
          state = available
          subnet_id = subnet-050f6fc499a455a97
          tags.% = 7
          tags.Environment = development
          tags.Infrastructure = No
          tags.Name = **redacted** NAT GW AZ 1
          vpc_id = vpc-057a1208002394e1b
      module.vpc_private_route.data.aws_nat_gateway.az2:
          id = nat-0325fe2ba1184815b
          allocation_id = eipalloc-0df309e8b533b35b6
          network_interface_id = eni-00e850031318b2a41
          private_ip = 172.16.254.92
          public_ip = 3.88.44.14
          state = available
          subnet_id = subnet-0191ae48f099aa808
          tags.% = 7
          tags.Infrastructure = No
          tags.Name = **redacted** NAT GW AZ 2
          vpc_id = vpc-057a1208002394e1b
      module.vpc_private_route.data.aws_subnet_ids.private:
          id = vpc-057a1208002394e1b
          ids.# = 2
          ids.1528047303 = subnet-03a4f5228ae9f1714
          ids.1908543416 = subnet-0d915cc4899877eb9
          tags.% = 1
          tags.Name = *Private*
          vpc_id = vpc-057a1208002394e1b
  </code></pre>
  
  <p><strong>What should I be doing different</strong> to cause this TF Module to wait for the resources to be created before polling for the resource? In Ansible I could just issue a wait command or run a loop searching for criteria before proceeding.</p>
  
  <p>Thank you for your thoughts!</p>
  
  <p><strong>PLEASE NOTE</strong> all of the "ids" shown in this output will be dead before you read this post. All data has been sanitized based on environmental security policies.</p>
  
Tags: <terraform><terraform-module>
Title: How to make Terraform Modules wait for resources to be created in place of using computed values
UserDisplayName: Steven K7FAQ
ThreadText: # How to make Terraform Modules wait for resources to be created in place of using computed values
  
  (Asked by: username_0 on 2019-01-30)
  
  Today I am working on building out several custom Terraform Modules. The issue that I am trying to figure out how to work around dependencies within modules. Until TF 0.12 is released we cannot declare a module to be dependent upon another module. So, in this root level main.tf:
  
  ```
  # ROOT level main.tf
  # -------------------------------------------------------------------
  # Create NAT Gateway - Associates EIP as well
  # -------------------------------------------------------------------
  module "vpc_nat_gateway" {
    source            = "./vpc_nat_gateway"
    vpc_id            = "${ module.vpc.id }"
    public_subnet_ids = "${ module.vpc_subnets.public_subnet_ids }"
    private_cidr      = "${ var.private_cidr }"
    common_tags       = "${ local.common_tags }"
  }
  
  # -------------------------------------------------------------------
  # Create Private Routes
  # -------------------------------------------------------------------
  module "vpc_private_route" {
    source         = "./vpc_private_route"
    vpc_id.        = "${ module.vpc.id }"
    nat_gateway_id = "${ module.vpc_nat_gateway.nat_gateway_id }"
    common_tags    = "${ local.common_tags }"
  }
  
  # vpc_private_route module - main.tf
  data "aws_nat_gateway" "az1" {
    vpc_id = "${ var.vpc_id }"
  
    tags {
      Name = "*NAT GW AZ 1"
    }
  }
  
  data "aws_nat_gateway" "az2" {
    vpc_id = "${ var.vpc_id }"
  
    tags {
      Name = "*NAT GW AZ 2"
    }
  }
  
  ```
  
  The result output is:
  
  ```
  ------ SNIP -----
  module.vpc_nat_gateway.aws_nat_gateway.nat[1]: Creation complete after 1m50s (ID: nat-02a7f4279cec3a6c8)
  module.vpc_nat_gateway.aws_nat_gateway.nat.0: Still creating... (2m0s elapsed)
  module.vpc_nat_gateway.aws_nat_gateway.nat[0]: Creation complete after 2m0s (ID: nat-0695a12d9c0305e4c)
  
      Error: Error applying plan:
  
      3 error(s) occurred:
  
      * module.vpc_private_route.data.aws_subnet_ids.private: data.aws_subnet_ids.private: no matching subnet found for vpc with id vpc-0b530d1885e74067b
      * module.vpc_private_route.data.aws_nat_gateway.az2: data.aws_nat_gateway.az2: no matching NAT gateway found: {
      Filter: [{
          Name: "vpc-id",
          Values: ["vpc-0b530d1885e74067b"]
          },{
          Name: "tag:Name",
          Values: ["*NAT GW AZ 2"]
          }]
      }
      * module.vpc_private_route.data.aws_nat_gateway.az1: data.aws_nat_gateway.az1: no matching NAT gateway found: {
      Filter: [{
          Name: "vpc-id",
          Values: ["vpc-0b530d1885e74067b"]
          },{
          Name: "tag:Name",
          Values: ["*NAT GW AZ 1"]
          }]
      }
  
  ```
  
  As observed in the output the Nat Gateways are created. `Terraform show` output tells us the Filters are correct:
  
  ```
      module.vpc_nat_gateway.aws_nat_gateway.nat.0:
          id = nat-0695a12d9c0305e4c
          allocation_id = eipalloc-023ca087ad4fb830e
          network_interface_id = eni-015e39fc8d3bc0de3
          private_ip = 172.16.254.16
          public_ip = 18.215.5.116
          subnet_id = subnet-0f2c039e8fd804f30
          tags.% = 7
          tags.Environment = development
          tags.Infrastructure = No
          tags.Name = **redacted** NAT GW AZ 1
      module.vpc_nat_gateway.aws_nat_gateway.nat.1:
          id = nat-02a7f4279cec3a6c8
          allocation_id = eipalloc-0a95264c2eef26673
          network_interface_id = eni-03bddcca2fbeeff44
          private_ip = 172.16.254.84
          public_ip = 3.91.167.246
          subnet_id = subnet-08ee61f3aa43acbe9
          tags.% = 7
          tags.Environment = development
          tags.Infrastructure = No
          tags.Name = **redacted** NAT GW AZ 2
  
  ```
  
  Executing a subsequent `terraform apply` runs without any errors.
  
  ```
  # Yes, the IDs are different in this example than from above.
  # ---- SNIP ----
      module.vpc_private_route.data.aws_nat_gateway.az1:
          id = nat-0c127e538a26b2bd5
          allocation_id = eipalloc-01775b8e88502d4b9
          network_interface_id = eni-0b0bd2203bd3f5873
          private_ip = 172.16.254.45
          public_ip = 3.83.199.207
          state = available
          subnet_id = subnet-050f6fc499a455a97
          tags.% = 7
          tags.Environment = development
          tags.Infrastructure = No
          tags.Name = **redacted** NAT GW AZ 1
          vpc_id = vpc-057a1208002394e1b
      module.vpc_private_route.data.aws_nat_gateway.az2:
          id = nat-0325fe2ba1184815b
          allocation_id = eipalloc-0df309e8b533b35b6
          network_interface_id = eni-00e850031318b2a41
          private_ip = 172.16.254.92
          public_ip = 3.88.44.14
          state = available
          subnet_id = subnet-0191ae48f099aa808
          tags.% = 7
          tags.Infrastructure = No
          tags.Name = **redacted** NAT GW AZ 2
          vpc_id = vpc-057a1208002394e1b
      module.vpc_private_route.data.aws_subnet_ids.private:
          id = vpc-057a1208002394e1b
          ids.# = 2
          ids.1528047303 = subnet-03a4f5228ae9f1714
          ids.1908543416 = subnet-0d915cc4899877eb9
          tags.% = 1
          tags.Name = *Private*
          vpc_id = vpc-057a1208002394e1b
  
  ```
  
  **What should I be doing different** to cause this TF Module to wait for the resources to be created before polling for the resource? In Ansible I could just issue a wait command or run a loop searching for criteria before proceeding.
  
  Thank you for your thoughts!
  
  **PLEASE NOTE** all of the "ids" shown in this output will be dead before you read this post. All data has been sanitized based on environmental security policies.
  
  **Tags:** terraform, terraform-module
  
  
  ---
  
  ## 4 answers
  
  ### Answer by username_1 on 2020-04-08. Score: 7
  
  **Update: As of TF 0.13x, `depends_on` is supported to create dependencies between modules. Using `depends_on` should be preferable over using the method detailed below.**
  
  The previous most popular answer is out of date with Terraform 0.12.24.
  
  `depends_on` is a protected variable, and cannot be used in a `module`.
  In addition there are a few syntax differences.
  
  I've updated the example below.
  
  ```
  # ROOT level main.tf
  # -------------------------------------------------------------------
  # Create NAT Gateway - Associates EIP as well
  # -------------------------------------------------------------------
  module "vpc_nat_gateway" {
    source            = "./vpc_nat_gateway"
    vpc_id            = module.vpc.id
    public_subnet_ids = module.vpc_subnets.public_subnet_ids
    private_cidr      = var.private_cidr
    common_tags       = local.common_tags
  }
  
  # -------------------------------------------------------------------
  # Create Private Routes
  # -------------------------------------------------------------------
  module "vpc_private_route" {
    source         = "./vpc_private_route"
    vpc_id.        = module.vpc.id
    nat_gateway_id = module.vpc_nat_gateway.nat_gateway_id
    common_tags    = local.common_tags
  
    # Depends is a custom variable, depends_on is a reserved keyword.
    depends = [module.vpc_nat_gateway.nat_gateway_id]
  }
  
  ```
  
  ```
  # vpc_private_route module - main.tf
  variable "depends" {
    default = []
  }
  
  resource "null_resource" "depends_on" {
    triggers = {
      depends_on = "${join("", var.depends)}"
    }
  }
  
  data "aws_nat_gateway" "az1" {
    vpc_id = var.vpc_id
  
    depends_on = [
      null_resource.depends_on
    ]
  }
  
  data "aws_nat_gateway" "az2" {
    vpc_id = var.vpc_id
  
    depends_on = [
      null_resource.depends_on
    ]
  }
  
  ```
  
  
  ---
  
  ### Answer by username_2 on 2020-11-27. Score: 5
  
  These are hacks (understandably as you couldn't explicitly do this in Terraform < 0.13).
  
  Now however, with 0.13, we have `depends_on` for modules: <https://github.com/hashicorp/terraform/blob/v0.13/CHANGELOG.md#0130-august-10-2020>
  
  
  ---
  
  ### Answer by username_3 on 2019-02-01. Score: 4
  
  There is a hacky workaround for getting Terraform to do module dependencies. You can force the module to be aware of the Terraform calling it like this:
  
  ```
  # ROOT level main.tf
  # -------------------------------------------------------------------
  # Create NAT Gateway - Associates EIP as well
  # -------------------------------------------------------------------
  module "vpc_nat_gateway" {
    source            = "./vpc_nat_gateway"
    vpc_id            = "${ module.vpc.id }"
    public_subnet_ids = "${ module.vpc_subnets.public_subnet_ids }"
    private_cidr      = "${ var.private_cidr }"
    common_tags       = "${ local.common_tags }"
  }
  
  # -------------------------------------------------------------------
  # Create Private Routes
  # -------------------------------------------------------------------
  module "vpc_private_route" {
    source         = "./vpc_private_route"
    vpc_id.        = "${ module.vpc.id }"
    nat_gateway_id = "${ module.vpc_nat_gateway.nat_gateway_id }"
    common_tags    = "${ local.common_tags }"
  
    depends_on = ["${module.vpc_nat_gateway.nat_gateway_id}"]
  }
  
  ```
  
  ```
  # vpc_private_route module - main.tf
  variable "depends_on" {
    default = []
  }
  
  resource "null_resource" "depends_on" {
    triggers {
      depends_on = "${join("", var.depends_on)}"
    }
  }
  
  data "aws_nat_gateway" "az1" {
    vpc_id = "${ var.vpc_id }"
  
    tags {
      Name = "*NAT GW AZ 1"
    }
  
    depends_on = [
      "null_resource.depends_on"
    ]
  }
  
  data "aws_nat_gateway" "az2" {
    vpc_id = "${ var.vpc_id }"
  
    tags {
      Name = "*NAT GW AZ 2"
    }
  
    depends_on = [
      "null_resource.depends_on"
    ]
  }
  
  ```
  
  It adds a lot of boilerplate but you will get the desired effect.
  
  > **Comments:**
  > **username_0**: Thank you @username_3 for this input and excellent example. I will try this my next day in office and report back.  
  
  ---
  
  ### Answer by username_4 on 2024-05-09. Score: 0
  
  I've not tried this, but you could have a null\_resource with a local-exec running a sleep command and make your resource dependent on that resource with a depends\_on lifecycle argument.
  
  
  ---
  
  