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