Need help with your JSON?
Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool
Terraform JSON Configuration File Best Practices
Terraform primarily uses HashiCorp Configuration Language (HCL) for writing infrastructure code. However, it also supports JSON-encoded configuration files, often referred to as TFJSON. While HCL is generally preferred for its readability and features like comments and interpolation syntax, understanding TFJSON and its best practices is crucial for specific use cases, particularly when generating configurations programmatically.
This article explores the structure of TFJSON and provides guidance on when and how to use it effectively, ensuring your Terraform codebase remains maintainable and understandable.
When to Use TFJSON (and When Not To)
HCL is the recommended language for human-written Terraform configurations. Its design focuses on readability and includes features like native support for lists, maps, and string interpolation that are more verbose in JSON.
Use TFJSON primarily for:
- Machine Generation: When another program (like a custom script or tool) needs to generate Terraform configuration files dynamically. JSON is a standard data interchange format and is easy to output from most programming languages.
- Integration with Other Tools: Some tools or APIs might output configuration snippets or data in JSON format that can be directly consumed by Terraform.
- Specific, Simple Structures: Occasionally, for very simple variable definitions or data sources where the structure is inherently JSON-like, it might be used, though HCL is still often clearer.
Avoid TFJSON for:
- Human-Written Configurations: HCL is significantly more pleasant to read and write for humans.
- Complex Logic: Interpolation, functions, loops (like `for_each` or `count`), conditionals, and data source lookups are much more cumbersome or impossible to express directly within TFJSON compared to HCL. You'd typically generate the *final* JSON output that represents the *result* of such logic defined elsewhere.
Structure of a TFJSON File
A TFJSON file is a single JSON object where keys represent Terraform block types (like `resource`, `variable`, `output`, `provider`, `terraform`, etc.). The values associated with these keys are JSON objects or arrays of objects that define the blocks.
Here's a breakdown of common top-level keys:
- `"resource"`: Defines infrastructure resources. The value is an object where keys are the resource types (e.g., `"aws_instance"`) and values are objects where keys are the resource local names (e.g., `"my_server"`).
- `"variable"`: Defines input variables. The value is an object where keys are the variable names.
- `"output"`: Defines output values. The value is an object where keys are the output names.
- `"provider"`: Configures providers. The value is an object where keys are provider names (e.g., `"aws"`).
- `"data"`: Defines data sources. Similar structure to `"resource"`.
- `"terraform"`: Configures Terraform settings (e.g., required version, backend).
Basic TFJSON Structure Example:
{
"terraform": {
"required_version": ">= 1.0.0"
},
"provider": {
"aws": {
"region": "us-east-1"
}
},
"variable": {
"instance_type": {
"description": "Type of EC2 instance",
"type": "string",
"default": "t2.micro"
}
},
"resource": {
"aws_instance": {
"web_server": {
"ami": "ami-0abcdef1234567890",
"instance_type": "${var.instance_type}",
"tags": {
"Name": "HelloWorldServer"
}
}
}
},
"output": {
"instance_id": {
"description": "ID of the EC2 instance",
"value": "${aws_instance.web_server.id}"
}
}
}
Notice the use of interpolation syntax (`$}`) within JSON strings. This is how you reference variables, resource attributes, etc., but it lacks the syntax highlighting and clarity of HCL.
TFJSON Best Practices
If you must use TFJSON, adhere to these practices to minimize headaches:
- Prefer HCL Whenever Possible: This is the most important best practice. Only resort to TFJSON when automation necessitates it.
- Keep Generated JSON Simple: If generating JSON, generate the simplest structure possible. Avoid embedding complex conditional logic or loops that could potentially be handled in HCL if the generation process were different. Generate static values or simple references where possible.
- Use Clear Key Names: Follow standard Terraform naming conventions for resource types, local names, variable names, etc. JSON keys are strings and should be descriptive.
- Use Standard JSON Formatting: Ensure the generated JSON is valid and consistently formatted. Use spaces or tabs consistently. This aids readability slightly, even though JSON is less human-friendly than HCL.
- Handle Interpolation Carefully: While interpolation works in TFJSON strings, it can quickly become hard to read. Ensure interpolated strings are correct and easy to identify. For complex expressions, consider if the generation script can evaluate parts of the expression and output a simpler string.
Interpolation Example:
"instance_type": "${var.instance_type}",
vs. HCL:
instance_type = var.instance_type
- Validate Generated Files: Always validate generated TFJSON files using `terraform fmt` (which can convert to HCL if needed for inspection) and `terraform validate`.
Validation Command:
terraform validate
Formatting/Conversion Command:
terraform fmt -json -recursive
Running `terraform fmt` on TFJSON files will reformat them. You can also use `terraform fmt -json -recursive > output.tf.json` to read HCL and output TFJSON. Running `terraform fmt -recursive` on TFJSON will convert it to HCL. Use this for inspection!
- Version Control Generated Files: Check generated TFJSON files into version control. This allows tracking changes, code reviews, and understanding the output of your generation scripts.
- Document the Generation Process: Clearly document *how* the TFJSON files are generated. What script? What inputs does it take? This is vital for maintainability.
- Use TFJSON Only for the Necessary Parts: You can mix TFJSON (`.tf.json`) and HCL (`.tf`) files in the same directory. Use TFJSON only for the specific parts that *must* be generated, and keep the rest in HCL.
Converting Between HCL and TFJSON
Terraform's `fmt` command can perform this conversion, which is incredibly useful for understanding the TFJSON structure corresponding to HCL or for inspecting generated JSON in a more human-readable HCL format.
Example HCL:
variable "region" {
description = "AWS Region"
type = string
default = "us-east-1"
}
Equivalent TFJSON:
{
"variable": {
"region": {
"description": "AWS Region",
"type": "string",
"default": "us-east-1"
}
}
}
You can test this conversion yourself using `terraform fmt`.
Potential Pitfalls
- Readability Issues: JSON is inherently less readable than HCL for complex configurations due to the lack of comments and verbose syntax for lists/maps.
- Debugging Difficulty: Tracking down syntax errors or logical issues in large, generated TFJSON files can be challenging compared to debugging HCL.
- Escaping Characters: Managing escaping within JSON strings, especially for interpolation or complex expressions, can be error-prone when generating the JSON.
- Lack of IDE Support: Most IDEs and text editors have excellent HCL support (syntax highlighting, snippets, validation). TFJSON support is often limited to basic JSON features.
Conclusion
While TFJSON is a valid format supported by Terraform, it shines best in specific scenarios like machine generation. For human-authored configurations, HCL remains the clear choice due to its superior readability, expressiveness, and tooling support.
If your workflow requires generating Terraform configuration, using TFJSON is a powerful option. By following the best practices outlined above — prioritizing HCL, keeping generated JSON simple, validating output, and documenting the process — you can effectively leverage TFJSON without sacrificing the maintainability of your infrastructure code. Always remember that TFJSON should serve the purpose of automation, not replace the benefits of HCL for human users.
Need help with your JSON?
Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool