Terraform Template: JSON formatting won't work, tftpl won't format

I have a AWS Task Definition Template in JSON. Which looks something like this:

      "name": "${container_name}",
      "image": "${image_name}",
      "essential": true,
      "portMappings": [
          "containerPort": ${container_port},
          "hostPort": ${host_port}
          "containerPort": ${soketRoot_port},
          "hostPort": ${soketRootHost_port}
      "Environment": [
        {"name" : "NODE_ENV", "value" : "${node_env}"},
        {"name" : "DB_PORT", "value" : "${DB_PORT}"},

Now, this will not auto-format no matter what I do.

  1. If I use json extension, it will complain ${container_port} is not valid element.
  2. If I use json extension, and wrap it up in a string like this: "${container_port}", it will fail during plan because it expects int.
  3. If I use .tftpl, and set Terraform as formatter, well, it shows all sort of error as , expected near :.

How do you guys format your template files? It is annoying because it’s a really long file, and since it does not format properly, I end up relying on search instead of just looking into formatted blocks.

Is there any solution to this?

Hi @naishe,

Although you didn’t mention it explicitly in your question, I’m guessing from context that you are using the templatefile function and the example you’ve shown is the content of the file you passed as the first argument to that function, whereas container_name and so forth are the variables you’ve passed in the second argument to that function.

The templatefile function doesn’t vary its behavior based on the filename suffix, so I’m not sure how to explain it behaving differently depending on what you name the file.

The documentation section Generating JSON or YAML from a template describes the recommended way to generate JSON from a template, which is to write a template that consists entirely of a single call to the jsonencode function so that Terraform’s built-in JSON encoder can be responsible for generating the correct JSON syntax, and so you only need to worry about describing the needed data structure using the Terraform expression syntax.

The JSON example you shared here seems to be incomplete, so I can’t show a full working example but I below is an example showing the subset of the data you included in your snippet:

    name = container_name
    image = image_name
    essential = true
    portMappings = [
        containerPort = container_port
        hostPort = host_port
        containerPort = soketRoot_port
        hostPort = soketRootHost_port
    Environment = [
      { name = "NODE_ENV", value = node_env },
      { name = "DB_PORT", value = DB_PORT },

There are a few different components to this example that I want to draw attention to:

  • The whole template begins with ${ and ends with }, which makes this entire template a single interpolation sequence. That syntax means to evaluate the expression inside, which should return a string, and to replace the interpolation sequence with that string.
  • The expression inside is a call to the jsonencode function. Since your goal is to produce a JSON array, we use [ ... ] brackets to construct a Terraform tuple value, which you can see in the jsonencode docs will translate to a JSON array.
  • Everything inside that is normal Terraform expressions like you would typically expect to see in .tf files as the value for a resource argument. That means it’s valid to refer to any of the template variables that are in scope, without any special delimiters to mark them as variables. For example, container_name will be replaced by the value of the variable of that name.

Since this is Terraform template and expression syntax rather than JSON syntax, the JSON syntax support in your text editor won’t be able to work with it, but a Terraform-specific extension might be able to. (Though most editor extensions only support the main language in .tf files, and don’t yet have special support for standalone templates.)