1--- 2layout: "language" 3page_title: "JSON Configuration Syntax - Configuration Language" 4sidebar_current: "docs-config-syntax-json" 5description: |- 6 Details about the JSON-compatible Terraform language syntax, including file structure, expression mapping, and blocks. 7--- 8 9# JSON Configuration Syntax 10 11Most Terraform configurations are written in 12[the native Terraform language syntax](/docs/language/syntax/configuration.html), which is designed to be 13relatively easy for humans to read and update. 14 15Terraform also supports an alternative syntax that is JSON-compatible. This 16syntax is useful when generating portions of a configuration programmatically, 17since existing JSON libraries can be used to prepare the generated 18configuration files. 19 20The JSON syntax is defined in terms of the native syntax. Everything that can 21be expressed in native syntax can also be expressed in JSON syntax, but some 22constructs are more complex to represent in JSON due to limitations of the 23JSON grammar. 24 25Terraform expects native syntax for files named with a `.tf` suffix, and 26JSON syntax for files named with a `.tf.json` suffix. 27 28The low-level JSON syntax, just as with the native syntax, is defined in terms 29of a specification called _HCL_. It is not necessary to know all of the details 30of HCL syntax or its JSON mapping in order to use Terraform, and so this page 31summarizes the most important differences between native and JSON syntax. 32If you are interested, you can find a full definition of HCL's JSON syntax 33in [its specification](https://github.com/hashicorp/hcl/blob/hcl2/json/spec.md). 34 35## JSON File Structure 36 37At the root of any JSON-based Terraform configuration is a JSON object. The 38properties of this object correspond to the top-level block types of the 39Terraform language. For example: 40 41```json 42{ 43 "variable": { 44 "example": { 45 "default": "hello" 46 } 47 } 48} 49``` 50 51Each top-level object property must match the name of one of the expected 52top-level block types. Block types that expect labels, such as `variable` 53shown above, are represented by one nested object value for each level 54of label. `resource` blocks expect two labels, so two levels of nesting 55are required: 56 57```json 58{ 59 "resource": { 60 "aws_instance": { 61 "example": { 62 "instance_type": "t2.micro", 63 "ami": "ami-abc123" 64 } 65 } 66 } 67} 68``` 69 70After any nested objects representing the labels, finally one more nested 71object represents the body of the block itself. In the above examples, the 72`default` argument for `variable "example"` and the `instance_type` and 73`ami` arguments for `resource "aws_instance" "example"` are specified. 74 75Taken together, the above two configuration files are equivalent to the 76following blocks in the native syntax: 77 78```hcl 79variable "example" { 80 default = "hello" 81} 82 83resource "aws_instance" "example" { 84 instance_type = "t2.micro" 85 ami = "ami-abc123" 86} 87``` 88 89Within each top-level block type the rules for mapping to JSON are slightly 90different (see the [block-type-specific exceptions](#block-type-specific-exceptions) below), but the following general rules apply in most cases: 91 92* The JSON object representing the block body contains properties that 93 correspond either to argument names or to nested block type names. 94 95* Where a property corresponds to an argument that accepts 96 [arbitrary expressions](/docs/language/expressions/index.html) in the native syntax, the 97 property value is mapped to an expression as described under 98 [_Expression Mapping_](#expression-mapping) below. For arguments that 99 do _not_ accept arbitrary expressions, the interpretation of the property 100 value depends on the argument, as described in the 101 [block-type-specific exceptions](#block-type-specific-exceptions) 102 given later in this page. 103 104* Where a property name corresponds to an expected nested block type name, 105 the value is interpreted as described under 106 [_Nested Block Mapping_](#nested-block-mapping) below, unless otherwise 107 stated in [the block-type-specific exceptions](#block-type-specific-exceptions) 108 given later in this page. 109 110## Expression Mapping 111 112Since JSON grammar is not able to represent all of the Terraform language 113[expression syntax](/docs/language/expressions/index.html), JSON values interpreted as expressions 114are mapped as follows: 115 116| JSON | Terraform Language Interpretation | 117| ------- | ------------------------------------------------------------------------------------------------------------- | 118| Boolean | A literal `bool` value. | 119| Number | A literal `number` value. | 120| String | Parsed as a [string template][] and then evaluated as described below. | 121| Object | Each property value is mapped per this table, producing an `object(...)` value with suitable attribute types. | 122| Array | Each element is mapped per this table, producing a `tuple(...)` value with suitable element types. | 123| Null | A literal `null`. | 124 125[string template]: /docs/language/expressions/strings.html#string-templates 126 127When a JSON string is encountered in a location where arbitrary expressions are 128expected, its value is first parsed as a [string template][] 129and then it is evaluated to produce the final result. 130 131If the given template consists _only_ of a single interpolation sequence, 132the result of its expression is taken directly, without first converting it 133to a string. This allows non-string expressions to be used within the 134JSON syntax: 135 136```json 137{ 138 "output": { 139 "example": { 140 "value": "${aws_instance.example}" 141 } 142 } 143} 144``` 145 146The `output "example"` declared above has the object value representing the 147given `aws_instance` resource block as its value, rather than a string value. 148This special behavior does not apply if any literal or control sequences appear 149in the template; in these other situations, a string value is always produced. 150 151## Nested Block Mapping 152 153When a JSON object property is named after a nested block type, the value 154of this property represents one or more blocks of that type. The value of 155the property must be either a JSON object or a JSON array. 156 157The simplest situation is representing only a single block of the given type 158when that type expects no labels, as with the `lifecycle` nested block used 159within `resource` blocks: 160 161```json 162{ 163 "resource": { 164 "aws_instance": { 165 "example": { 166 "lifecycle": { 167 "create_before_destroy": true 168 } 169 } 170 } 171 } 172} 173``` 174 175The above is equivalent to the following native syntax configuration: 176 177```hcl 178resource "aws_instance" "example" { 179 lifecycle { 180 create_before_destroy = true 181 } 182} 183``` 184 185When the nested block type requires one or more labels, or when multiple 186blocks of the same type can be given, the mapping gets a little more 187complicated. For example, the `provisioner` nested block type used 188within `resource` blocks expects a label giving the provisioner to use, 189and the ordering of provisioner blocks is significant to decide the order 190of operations. 191 192The following native syntax example shows a `resource` block with a number 193of provisioners of different types: 194 195```hcl 196resource "aws_instance" "example" { 197 # (resource configuration omitted for brevity) 198 199 provisioner "local-exec" { 200 command = "echo 'Hello World' >example.txt" 201 } 202 provisioner "file" { 203 source = "example.txt" 204 destination = "/tmp/example.txt" 205 } 206 provisioner "remote-exec" { 207 inline = [ 208 "sudo install-something -f /tmp/example.txt", 209 ] 210 } 211} 212``` 213 214In order to preserve the order of these blocks, you must use a JSON array 215as the direct value of the property representing this block type, as in 216this JSON equivalent of the above: 217 218```json 219{ 220 "resource": { 221 "aws_instance": { 222 "example": { 223 "provisioner": [ 224 { 225 "local-exec": { 226 "command": "echo 'Hello World' >example.txt" 227 } 228 }, 229 { 230 "file": { 231 "source": "example.txt", 232 "destination": "/tmp/example.txt" 233 } 234 }, 235 { 236 "remote-exec": { 237 "inline": ["sudo install-something -f /tmp/example.txt"] 238 } 239 } 240 ] 241 } 242 } 243 } 244} 245``` 246 247Each element of the `provisioner` array is an object with a single property 248whose name represents the label for each `provisioner` block. For block types 249that expect multiple labels, this pattern of alternating array and object 250nesting can be used for each additional level. 251 252If a nested block type requires labels but the order does _not_ matter, you 253may omit the array and provide just a single object whose property names 254correspond to unique block labels. This is allowed as a shorthand for the above 255for simple cases, but the alternating array and object approach is the most 256general. We recommend using the most general form if systematically converting 257from native syntax to JSON, to ensure that the meaning of the configuration is 258preserved exactly. 259 260### Comment Properties 261 262Although we do not recommend hand-editing of JSON syntax configuration files 263-- this format is primarily intended for programmatic generation and consumption -- 264a limited form of _comments_ are allowed inside JSON objects that represent 265block bodies using a special property name: 266 267```json 268{ 269 "resource": { 270 "aws_instance": { 271 "example": { 272 "//": "This instance runs the scheduled tasks for backup", 273 274 "instance_type": "t2.micro", 275 "ami": "ami-abc123" 276 } 277 } 278 } 279} 280``` 281 282In any object that represents a block body, properties named `"//"` are 283ignored by Terraform entirely. This exception does _not_ apply to objects 284that are being [interpreted as expressions](#expression-mapping), where this 285would be interpreted as an object type attribute named `"//"`. 286 287This special property name can also be used at the root of a JSON-based 288configuration file. This can be useful to note which program created the file. 289 290```json 291{ 292 "//": "This file is generated by generate-outputs.py. DO NOT HAND-EDIT!", 293 294 "output": { 295 "example": { 296 "value": "${aws_instance.example}" 297 } 298 } 299} 300``` 301 302## Block-type-specific Exceptions 303 304[inpage-block]: #block-type-specific-exceptions 305 306Certain arguments within specific block types are processed in a special way 307by Terraform, and so their mapping to the JSON syntax does not follow the 308general rules described above. The following sub-sections describe the special 309mapping rules that apply to each top-level block type. 310 311### `resource` and `data` blocks 312 313Some meta-arguments for the `resource` and `data` block types take direct 314references to objects, or literal keywords. When represented in JSON, the 315reference or keyword is given as a JSON string with no additional surrounding 316spaces or symbols. 317 318For example, the `provider` meta-argument takes a `<PROVIDER>.<ALIAS>` reference 319to a provider configuration, which appears unquoted in the native syntax but 320must be presented as a string in the JSON syntax: 321 322```json 323{ 324 "resource": { 325 "aws_instance": { 326 "example": { 327 "provider": "aws.foo" 328 } 329 } 330 } 331} 332``` 333 334This special processing applies to the following meta-arguments: 335 336* `provider`: a single string, as shown above 337* `depends_on`: an array of strings containing references to named entities, 338 like `["aws_instance.example"]`. 339* `ignore_changes` within the `lifecycle` block: if set to `all`, a single 340 string `"all"` must be given. Otherwise, an array of JSON strings containing 341 property references must be used, like `["ami"]`. 342 343Special processing also applies to the `type` argument of any `connection` 344blocks, whether directly inside the `resource` block or nested inside 345`provisioner` blocks: the given string is interpreted literally, and not 346parsed and evaluated as a string template. 347 348### `variable` blocks 349 350All arguments inside `variable` blocks have non-standard mappings to JSON: 351 352* `type`: a string containing a type expression, like `"string"` or `"list(string)"`. 353* `default`: a literal JSON value that can be converted to the given type. 354 Strings within this value are taken literally and _not_ interpreted as 355 string templates. 356* `description`: a literal JSON string, _not_ interpreted as a template. 357 358```json 359{ 360 "variable": { 361 "example": { 362 "type": "string", 363 "default": "hello" 364 } 365 } 366} 367``` 368 369### `output` blocks 370 371The `description` and `sensitive` arguments are interpreted as literal JSON 372values. The `description` string is not interpreted as a string template. 373 374The `value` argument is [interpreted as an expression](#expression-mapping). 375 376```json 377{ 378 "output": { 379 "example": { 380 "value": "${aws_instance.example}" 381 } 382 } 383} 384``` 385 386### `locals` blocks 387 388The value of the JSON object property representing the locals block type 389must be a JSON object whose property names are the local value names to 390declare: 391 392```json 393{ 394 "locals": { 395 "greeting": "Hello, ${var.name}" 396 } 397} 398``` 399 400The value of each of these nested properties is 401[interpreted as an expression](#expression-mapping). 402 403### `module` blocks 404 405The `source` and `version` meta-arguments must be given as literal strings. The 406values are not interpreted as string templates. 407 408The `providers` meta-argument must be given as a JSON object whose properties 409are the compact provider addresses to expose into the child module and whose 410values are the provider addresses to use from the current module, both 411given as literal strings: 412 413```json 414{ 415 "module": { 416 "example": { 417 "source": "hashicorp/consul/azurerm", 418 "version": "= 1.0.0", 419 "providers": { 420 "aws": "aws.usw1" 421 } 422 } 423 } 424} 425``` 426 427### `provider` blocks 428 429The `alias` and `version` meta-arguments must be given as literal strings. The 430values are not interpreted as string templates. 431 432```json 433{ 434 "provider": { 435 "aws": [ 436 { 437 "region": "us-east-1" 438 }, 439 { 440 "alias": "usw1", 441 "region": "us-west-1" 442 } 443 ] 444 } 445} 446``` 447 448### `terraform` blocks 449 450Since no settings within `terraform` blocks accept named object references or 451function calls, all setting values are taken literally. String values are not 452interpreted as string templates. 453 454Since only one `backend` block is allowed per `terraform` block, the compact 455block mapping can be used to represent it, with a nested object containing 456a single property whose name represents the backend type. 457 458```json 459{ 460 "terraform": { 461 "required_version": ">= 0.12.0", 462 "backend": { 463 "s3": { 464 "region": "us-west-2", 465 "bucket": "acme-terraform-states" 466 } 467 } 468 } 469} 470``` 471