# How to refer to variables in a JSON configuration file

**URL:** <https://discuss.hashicorp.com/t/how-to-refer-to-variables-in-a-json-configuration-file/34247>\
**Category:** Terraform\
**Created:** [January 13, 2022, 2:08pm UTC](https://discuss.hashicorp.com/t/how-to-refer-to-variables-in-a-json-configuration-file/34247 "2022-01-13T14:08:40Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![brandootr](https://sea2.discourse-cdn.com/hashicorp/user_avatar/discuss.hashicorp.com/brandootr/32/25096_2.png) [@brandootr](https://discuss.hashicorp.com/u/brandootr)\
**Post date:** [January 13, 2022, 2:08pm UTC](https://discuss.hashicorp.com/t/how-to-refer-to-variables-in-a-json-configuration-file/34247/1 "2022-01-13T14:08:40Z")

</div>

Is it possible to use variables within the json file example  
“security\_groups”: “module.nsg.security\_groups.id”

When I try, it just passes the string module.nsg.security\_groups.id I also tried ${module.nsg.security\_groupds.id)

---

<div class="post-metadata">

**Author:** ![apparentlymart](https://sea2.discourse-cdn.com/hashicorp/user_avatar/discuss.hashicorp.com/apparentlymart/32/702_2.png) [@apparentlymart](https://discuss.hashicorp.com/u/apparentlymart)\
**Post date:** [January 13, 2022, 8:18pm UTC](https://discuss.hashicorp.com/t/how-to-refer-to-variables-in-a-json-configuration-file/34247/2 "2022-01-13T20:18:07Z")

</div>

Hi @brandootr! You bumped a very old topic and so I’ve moved your question into a separate topic so we can discuss it without creating notification noise for those who participated in the original topic.

I assume you are talking about [the JSON variant of the Terraform language](https://www.terraform.io/language/syntax/json), which is to say that you are writing or generating `.tf.json` files to define your infrastructure objects.

In any situation where the native syntax would expect a general value expression (which includes all normal resource arguments), [the _Expression Mapping_](https://www.terraform.io/language/syntax/json#expression-mapping) describes how Terraform translates your JSON input into corresponding concepts from the native syntax.

Notice that the description of how Terraform interprets a string value says:

> Parsed as a [string template](https://www.terraform.io/language/expressions/strings#string-templates) and then evaluated as described below.

The subsequent paragraphs then go on to show an example of referring to another object using template interpolation inside a JSON string:

```auto
{
  "output": {
    "example": {
      "value": "${aws_instance.example}"
    }
  }
}

```

The above is showing a JSON declaration of an `output` block, whose native syntax equivalent would be the following:

```auto
output "example" {
  value = aws_instance.example
}

```

From your question it sounds like you already tried something like this and encountered an error. If the above doesn’t answer your question, it would be helpful if you could show the full, exact configuration you tried (the one where you tried `${module.nsg.security_groupds.id`) and the full error message Terraform returned in response to it, and then I can hopefully understand and explain why your particular attempt didn’t work.

---

<div class="post-metadata">

**Author:** ![brandootr](https://sea2.discourse-cdn.com/hashicorp/user_avatar/discuss.hashicorp.com/brandootr/32/25096_2.png) [@brandootr](https://discuss.hashicorp.com/u/brandootr)\
**Post date:** [January 17, 2022, 10:18pm UTC](https://discuss.hashicorp.com/t/how-to-refer-to-variables-in-a-json-configuration-file/34247/3 "2022-01-17T22:18:51Z")

</div>

My main.tf looks like this

```auto
data "template_file" "instance" {
  template = "${file("${path.module}/instance.json")}"

}
locals {
  instance = data.template_file.instance
}

```

My instance.json looks like this

```auto
{
    "UATDB01": {
        "AZ": "$${data.oci_identity_availability_domain.AD-1}",
        "env_number": "1",
        "instance_shape_config_memory_in_gbs": "60",
        "subnet_id": "$${data.oci_core_subnets.internal1.subnets[0].id}",
        "fault_domain": "FAULT-DOMAIN-1",
        "image_id": "$${data.oci_core_images.this.images[0].id}",
        "ocpu_count": "4",
        "shape": "VM.Standard.E3.Flex",
        "public_ip": "false",
        "security_groups": "$${module.nsg.security_groups.id}"
    },
    "UATDB02": {
        "AZ": "$${data.oci_identity_availability_domain.AD-1}",
        "env_number": "1",
        "instance_shape_config_memory_in_gbs": "60",
        "subnet_id": "$${data.oci_core_subnets.internal1.subnets[0].id}",
        "fault_domain": "FAULT-DOMAIN-1",
        "image_id": "$${data.oci_core_images.this.images[0].id}",
        "ocpu_count": "4",
        "shape": "VM.Standard.E3.Flex",
        "public_ip": "false",
        "security_groups": "$${module.nsg.security_groups.id}"
    }
}

```

My Module looks like this

```auto
module "instance" {
  source = “”
  for_each = data.template_file.instance
  compartment_id = oci_identity_compartment.this.id
  fault_domain = each.value.fault_domain
  AZ = "${each.value.AZ}"
  shape = each.value.shape
  security_groups = each.value.security_groups
  tags = module.environment.tags
  name = each.key
  instance_shape_config_memory_in_gbs = each.value.instance_shape_config_memory_in_gbs
  user_data = module.cloud_init.windows
  subnet_id = each.value.subnet_id
  image_id = each.value.image_id
  ocpu_count = each.value.ocpu_count
}

```

When I execute a Terraform plan I get this

```auto
168: ocpu_count = each.value.ocpu_count
    ├────────────────
    │ each.value is "{\r\n \"UATDB01\": {\r\n \"AZ\": \"$${data.oci_identity_availability_domain.AD-1}\",\r\n \"env_number\": \"1\",\r\n \"instance_shape_config_memory_in_gbs\": \"60\",\r\n \"subnet_id\": \"$${data.oci_core_subnets.internal1.subnets[0].id}\",\r\n \"fault_domain\": \"FAULT-DOMAIN-1\",\r\n     
   \"image_id\": \"$${data.oci_core_images.this.images[0].id}\",\r\n \"ocpu_count\": \"4\",\r\n \"shape\": \"VM.Standard.E3.Flex\",\r\n \"public_ip\": \"false\",\r\n \"security_groups\": \"$${module.nsg.security_groups.id}\"\r\n },\r\n \"UATDB02\": {\r\n \"AZ\": \"$${data.oci_identity_availability_domain.AD-1}\",\r\n \"env_number\": \"1\",\r\n \"instance_shape_config_memory_in_gbs\": \"60\",\r\n \"subnet_id\": \"$${data.oci_core_subnets.internal1.subnets[0].id}\",\r\n \"fault_domain\": \"FAULT-DOMAIN-1\",\r\n \"image_id\": \"$${data.oci_core_images.this.images[0].id}\",\r\n \"ocpu_count\": \"4\",\r\n      
  \"shape\": \"VM.Standard.E3.Flex\",\r\n \"public_ip\": \"false\",\r\n \"security_groups\": \"$${module.nsg.security_groups.id}\"\r\n }\r\n}"

Can't access attributes on a primitive-typed value (string).

```

---

<div class="post-metadata">

**Author:** ![brandootr](https://sea2.discourse-cdn.com/hashicorp/user_avatar/discuss.hashicorp.com/brandootr/32/25096_2.png) [@brandootr](https://discuss.hashicorp.com/u/brandootr)\
**Post date:** [January 17, 2022, 10:19pm UTC](https://discuss.hashicorp.com/t/how-to-refer-to-variables-in-a-json-configuration-file/34247/4 "2022-01-17T22:19:53Z")

</div>

Also, I am using Terraform version v1.0.9 for Windows.

---

<div class="post-metadata">

**Author:** ![apparentlymart](https://sea2.discourse-cdn.com/hashicorp/user_avatar/discuss.hashicorp.com/apparentlymart/32/702_2.png) [@apparentlymart](https://discuss.hashicorp.com/u/apparentlymart)\
**Post date:** [January 18, 2022, 4:57pm UTC](https://discuss.hashicorp.com/t/how-to-refer-to-variables-in-a-json-configuration-file/34247/5 "2022-01-18T16:57:35Z")

</div>

Hi @brandootr,

What you have here is not a _JSON Configuration File_, but rather a Terraform template that happens to generate JSON. That might seem like a pedantic distinction to make, but it’s particularly important here because Terraform has no awareness that this template is generating JSON, and is instead just treating it like any other string template.

The relevant documentation is therefore [string template syntax](https://www.terraform.io/language/expressions/strings#string-templates), rather than the JSON Configuration Syntax I linked before.

With that said, I see that you are using the deprecated `template_file` data source here, rather than the current [`templatefile` function](https://www.terraform.io/language/functions/templatefile). The documentation for the current function includes [a section specifically about generating JSON or YAML from a template](https://www.terraform.io/language/functions/templatefile#generating-json-or-yaml-from-a-template), which shows our recommended way to do it, which allows you to describe the data structure using Terraform’s expression syntax rather than Terraform’s template syntax, and can therefore avoid annoying escaping, quoting, and delimiter-related problems.

First let’s see what it looks like to remove the deprecated `template_file` data source and use the `templatefile` function instead. The following configuration replaces what you showed as being in your `main.tf` file:

```auto
locals {
  instance = templatefile("${path.module}/instance.json", {})
}

```

If you _just_ change the above then I expect you’ll see just a slightly different version of the same error message you saw before, because Terraform is still parsing that file with the same template syntax, but now the parsing is happening inside Terraform itself rather than in the deprecated `hashicorp/template` provider.

From here there are two more problems to solve:

1. Passing the necessary data into the template rendering, so you can refer to it. Terraform templates are evaluated in their own separate namespace and so by default there are no variables available, but you can pass in extra variables using the second argument to `templatefile`, which I set to just `{}` (an empty object) in the above example.
2. Making the template use the recommended pattern so you can use Terraform expression syntax to generate the data structure and then have Terraform itself encode it as JSON for you, so that the JSON syntax will be guaranteed correct.

For the first of those, this template seems to need a few different values and so the goal is to pass each of those values into that second argument of `templatefile` using names that will make sense in the context of the template. I don’t know enough about your underlying system to know what names to pick here and so I’m going to make a guess here but you should of course feel free to rename and adjust here as needed. Again, this replaces my previous example, which in turn replaced your `main.tf` example:

```auto
locals {
  instance = templatefile("${path.module}/instance.json", {
    az = data.oci_identity_availability_domain.AD-1
    subnet_id = data.oci_core_subnets.internal1.subnets[0].id
    image_id = data.oci_core_images.this.images[0].id
    security_group_ids = module.nsg.security_groups.ids
  })
}

```

Notice that because the template namespace is separate from the Terraform module namespace, we can assign shorter meaningful names to each of the values passed in, which is what we’ll then use inside the template.

The `instance.json` file would then look something like the following, based on the advice on the `templatefile` documentation page about generating JSON:

```auto
${jsonencode({
  UATDB01 = {
    AZ = az
    env_number = "1"
    instance_shape_config_memory_in_gbs = "60"
    subnet_id = subnet_id
    fault_domain = "FAULT-DOMAIN-1"
    image_id = image_id
    ocpu_count = "4"
    shape = "VM.Standard.E3.Flex"
    public_ip = "false"
    security_groups = security_group_ids
  }
  UATDB02 = {
    AZ = az
    env_number = "1"
    instance_shape_config_memory_in_gbs = "60"
    subnet_id = subnet_id
    fault_domain = "FAULT-DOMAIN-1"
    image_id = image_id
    ocpu_count = "4"
    shape = "VM.Standard.E3.Flex"
    public_ip = "false"
    security_groups = security_group_ids
  }
})}

```

Notice that this template is really just one big interpolation sequence `${ ... }`, and so the result of the template is just the result if the expression inside. In this case it immediately calls [`jsonencode`](https://www.terraform.io/language/functions/jsonencode), and so the result is a JSON string.

The argument to `jsonencode` is any valid Terraform expression, whose result Terraform will convert to JSON using the mapping table in the `jsonencode` documentation, and so the result should be the same JSON data structure as described in your original example.

---

<div class="post-metadata">

**Author:** ![brandootr](https://sea2.discourse-cdn.com/hashicorp/user_avatar/discuss.hashicorp.com/brandootr/32/25096_2.png) [@brandootr](https://discuss.hashicorp.com/u/brandootr)\
**Post date:** [January 19, 2022, 1:28pm UTC](https://discuss.hashicorp.com/t/how-to-refer-to-variables-in-a-json-configuration-file/34247/6 "2022-01-19T13:28:12Z")

</div>

This is awesome information. Thank you so much. Let me make some modifications and see if I can get this to work.
