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