Terraform

Terraform Jsonencode Function – Definition & Examples

Terraform Jsonencode Function

What is the jsonencode function in Terraform?

jsonencode is a Terraform function that encodes a given value to a string using JSON syntax. It can be useful wherever you need to deal with JSON input, for example, creating an IAM user in AWS, or Policy in Azure.

What is the jsondecode function in Terraform?

The opposite of the jsonencode function, the jsondecode function in Terraform allows you to parse a JSON-formatted string and convert it into a data structure that you can use within your Terraform configurations.

It is useful wherever you need to convert your output to JSON and use the results elsewhere in your Terraform configuration.

Read more about other Terraform functions, expressions, and loops.

How to use the jsonencode Terraform function?

To play around with the jsonencode function, you can use the Terraform console. Simply type terraform console into your terminal to start.

Enter jsonencode({"hello"="world"}) — The output displayed will be in JSON format.

terraform jsonencode examples

Note that the jsonencode cannot directly map to all types available in JSON formatting because there are differences between how the types are represented between HCL (Hashicorp configuration language) and JSON.

Terraform to JSON data types are mapped as follows:

  • string — String
  • number — Number
  • bool — Bool
  • list(...) — Array
  • set(...) — Array
  • tuple(...) — Array
  • map(...) — Object
  • object(...) — Object
  • null — Null value

For the following examples, we will create a simple JSON file:

yoda.json

{
  "name": "Yoda",
  "age": 900,
  "city": "Dagobah System"
}

Example 1: Using JSON files as input variables and local variables

In this example, we will use the yoda.json file as an input variable, have Terraform use the jsondecode function in the locals, and then finally output the results.

variable "json_input" {
  description = "Path to the JSON input file"
  type        = string
}

locals {
  input_data = jsondecode(file(var.json_input))
}

output "name" {
  value = local.input_data.name
}

output "age" {
  value = local.input_data.age
}

output "city" {
  value = local.input_data.city
}
  1. We define a variable json_input to specify the path to the JSON input file.
  2. We decode the JSON content using the jsondecode function and store it in the local.input_data variable. The file function specifies we need to read the JSON contents from a file.
  3. We define outputs for each key in the JSON, making the data available for other parts of your Terraform code. It can be referenced elsewhere in your Terraform code using local.input_data.name , local.input_data.age , and local.input_data.city.

To run the code, in your terminal specify the variable directly with the -var flag, which points to the path of the yoda.json file:

terraform init
terraform apply -var="json_input=yoda.json"

Example 2: Passing in JSON via environment variables

In this example, we will define some JSON as an environment variable and pass it into our Terraform configuration.

To set the environment variables, run the following on the terminal:

export TF_VAR_json_input='{"name": "Yoda", "age": 900, "city": "Dagobah System"}'

Environment variables can be used to set Terraform variables using TF_VAR.

The _json_imput part defines the name of the variable we want to set. This can then be referenced directly in the Terraform code (without the need for the file function this time):

variable "json_input" {
  description = "JSON input"
  type        = string
  default     = ""
}

locals {
  input_data = jsondecode(var.json_input)
}

output "name" {
  value = local.input_data.name
}

output "age" {
  value = local.input_data.age
}

output "city" {
  value = local.input_data.city
}

To see the results, run:

terraform init
terraform apply
jsonencode terraform

Example 3: Decoding JSON strings to Terraform maps

In this example, we will output the values as a Terraform map and pass the JSON in directly on the terminal.

Note the outputs now have the values for each key contained in [""] .

variable "json_input" {
  description = "JSON input"
  type        = string
  default     = ""
}

locals {
  input_data = jsondecode(var.json_input)
}

output "name" {
  value = local.input_data["name"]
}

output "age" {
  value = local.input_data["age"]
}

output "city" {
  value = local.input_data["city"]
}

To test the output we can run:

terraform init
terraform apply -var='json_input={"name": "Yoda", "age": 900, "city": "Dagobah System"}'

Example 4: Using jsonencode in the template file

Suppose you have a template file, for example, a configuration file, and you want to include some data as a JSON-encoded string in that file.

Our template file looks like this:

{
  "app_config": ${app_config}
}

Our terraform configuration looks like this:

example4.tf

# Define a variable with configuration data
variable "app_config" {
  type = map(string)
  default = {
    name = "Yoda",
    age  = "900",
    city = "Dagobah System"
  }
}

# Render the template
data "template_file" "app_config_template" {
  template = file("template.tpl")
  vars = {
    app_config = jsonencode(var.app_config)
  }
}

# Create a local file to save the generated JSON config
resource "local_file" "app_config" {
  filename = "app_config.json"
  content  = data.template_file.app_config_template.rendered
}

First, the data is defined that you want to encode as a JSON string. This data could be a variable or a map within your Terraform configuration.

Next, we use the data "template_file" block to render a template file. The template attribute specifies the path to the template file, which is template.tpl. The vars attribute is used to pass variables into the template. In this case, we’re passing the app_config variable, but we use the jsonencode function to encode it as a JSON string.

Finally, we create a local file using the resource "local_file" block. This local file is used to save the generated JSON configuration.

We specify the filename attribute to set the path and name of the output file, which is app_config.json. The content attribute contains the rendered output from the template defined in the data "template_file" block. This content is obtained using data.template_file.app_config_template.rendered.

To run the example:

terraform init
terraform apply

On confirming the apply, a file called app_config.json will be generated in the local directory containing the map contents in JSON format:

{
  "app_config": {"age":"900","city":"Dagobah System","name":"Yoda"}
}

Example 5: Using jsonencode with the for loop

You can use jsonencode in conjunction with a for loop in Terraform to generate JSON data structures dynamically. In this example, we have a list of items, which we will encode into a JSON array using a for loop.

Our template.tpl file looks like this:

{
  "items": ${items_json}
}

example5.tf:

# Define a list of items
variable "items" {
  type    = list(string)
  default = ["Yoda", "Darth Vader", "Salacious Crumb"]
}

# Render the template
data "template_file" "items_template" {
  template = file("template.tpl")
  vars = {
    items_json = jsonencode([for item in var.items : { name = item }])
  }
}

# Create a local file to save the generated JSON
resource "local_file" "items_json" {
  filename = "items.json"
  content  = data.template_file.items_template.rendered
}

This time, inside the vars block, we use a for loop to iterate over each item in the var.items list. In each iteration, we create a map with the key “name” and the value as the current item. This list of maps is then passed to jsonencode to create a JSON array.

terraform init
terraform apply
terraform jsonencode policy

On confirmation of the apply, an items.json file is generated in the local directory containing the following JSON:

{
  "items": [{"name":"Yoda"},{"name":"Darth Vader"},{"name":"Salacious Crumb"}]
}

Example 6: Creating IAM policies using jsonencode function

Creating IAM policies in Terraform using the jsonencode function can be useful when you need to define fine-grained permissions for your AWS resources.

IAM policies are defined as JSON documents, and you can use the jsonencode function to create these policy documents in your Terraform configuration.

# Define a map of IAM policy statements
variable "iam_policy_statements" {
  type = list(object({
    action   = list(string)
    resource = string
  }))
  default = [
    {
      action   = ["s3:GetObject", "s3:ListBucket"]
      resource = "arn:aws:s3:::my-bucket/*"
    },
    {
      action   = ["s3:PutObject"]
      resource = "arn:aws:s3:::my-bucket/upload/*"
    },
    # Add more policy statements as needed
  ]
}

# Encode the IAM policy using jsonencode
locals {
  iam_policy_document = jsonencode({
    Version = "2012-10-17",
    Statement = [
      for statement in var.iam_policy_statements : {
        Action   = statement.action,
        Effect   = "Allow",
        Resource = statement.resource,
      }
    ]
  })
}

# Create an IAM policy
resource "aws_iam_policy" "example" {
  name        = "example-policy"
  description = "Example IAM policy"
  policy      = local.iam_policy_document
}

# Attach the policy to a user, group, or role as needed
  1. The variable iam_policy_statements represents a list of IAM policy statements. Each statement includes an action (a list of allowed actions) and a resource (the AWS resource that the actions apply to).
  2. The jsonencode function in the locals block is used to generate the JSON document for the IAM policy. We use a for loop to iterate over the policy statements defined in the variable and structure them into the required format for an IAM policy.
  3. The IAM policy is created using the aws_iam_policy resource. The policy attribute of this resource is set to the JSON-encoded IAM policy document from the locals block.
  4. Finally, you can attach the created policy to an IAM user, group, or role as needed by referencing the aws_iam_policy.example resource in the respective resource block (aws_iam_user_policy_attachmentaws_iam_group_policy_attachment, or aws_iam_role_policy_attachment).

Example 7: Creating Azure Policy definitions with jsonencode function

Azure Policy definitions are typically defined as JSON objects, and you can use jsonencode to create those JSON objects within your Terraform configuration.

The below example shows an Azure policy rule enforcing restrictions if certain tags are applied, which can be referenced elsewhere in your code by referring to policy_rule.

# Define an Azure Policy definition
resource "azurerm_policy_definition" "example" {
  name         = "example-policy"
  display_name = "Example Policy"
  description  = "An example Azure Policy definition"
  policy_type  = "Custom"
  mode         = "All"

  metadata {
    category = "General"
  }

  # Encode the policy rule using jsonencode
  policy_rule = jsonencode({
    if {
      allOf = [
        {
          field = "tags['environment']"
          equals = "production"
        },
        {
          field = "tags['costCenter']"
          notLike = "HR-*"
        }
      ]
    }
    then {
      effect = "deny"
    }
  })
}

After defining the policy, you can associate it with a policy assignment to enforce it within a particular scope, such as the subscription level:

resource "azurerm_policy_assignment" "example" {
  name                 = "example-assignment"
  scope                = "/subscriptions/<subscription_id>"
  policy_definition_id = azurerm_policy_definition.example.id
}

What is the difference between jsonencode and heredoc Terraform?

Where, jsonencode is specifically for encoding structured data into a JSON string, making it suitable for creating JSON-based configuration files or policy definitions, Heredoc is a way to include multi-line strings directly in your Terraform configuration.

It allows you to define a block of text without escaping special characters or worrying about JSON formatting. Heredoc is often used for embedding text, scripts, or configuration files in your Terraform code.

For reference, Heredoc syntax within a resource block looks like the below:

resource "example_resource" "example" {
  config_script = <<-EOT
    echo "This is a sample script"
  EOT
}

Key points

Handling JSON files in your Terraform configuration files can be achieved using the jsonencode and the opposite jsondecode functions. Data structures can be manipulated as needed to read in or create new JSON files for common purposes, such as IAM assignments in AWS or creating Azure Policy.

We encourage you also to explore how Spacelift makes it easy to work with Terraform. If you need any help managing your Terraform infrastructure, building more complex workflows based on Terraform, and managing AWS credentials per run, instead of using a static pair on your local machine, Spacelift is a fantastic tool for this. It supports Git workflows, policy as code, programmatic configuration, context sharing, drift detection, and many more great features right out of the box. You can check it for free, by creating a trial account.

Note: New versions of Terraform will be placed under the BUSL license, but everything created before version 1.5.x stays open-source. OpenTofu is an open-source version of Terraform that will expand on Terraform’s existing concepts and offerings. It is a viable alternative to HashiCorp’s Terraform, being forked from Terraform version 1.5.6. OpenTofu retained all the features and functionalities that had made Terraform popular among developers while also introducing improvements and enhancements. OpenTofu works with your existing Terraform state file, so you won’t have any issues when you are migrating to it.

Manage Terraform Better with Spacelift

Build more complex workflows based on Terraform using policy as code, programmatic configuration, context sharing, drift detection, resource visualization and many more.

Start free trial