| --- |
| page_title: Attributes as Blocks - Configuration Language |
| description: >- |
| For historical reasons, certain arguments within resource blocks can use |
| either |
| |
| block or attribute syntax. |
| --- |
| |
| # Attributes as Blocks |
| |
| -> **Note:** This page is an appendix to the Terraform documentation. Most users do not need to know the full details of this behavior. |
| |
| ## Summary |
| |
| Many resource types use repeatable nested blocks to manage collections of |
| sub-objects related to the primary resource. |
| |
| Rarely, some resource types _also_ support an argument with the same name as a |
| nested block type, and will purge any sub-objects of that type if that argument |
| is set to an empty list (`<ATTR> = []`). |
| |
| Most users do not need to know any further details of this "nested block or |
| empty list" behavior. However, read further if you need to: |
| |
| - Use Terraform's [JSON syntax](/language/syntax/json) with this |
| type of resource. |
| - Create a reusable module that wraps this type of resource. |
| |
| ## Details |
| |
| In Terraform v0.12 and later, the language makes a distinction between |
| [argument syntax and nested block syntax](/language/syntax/configuration#arguments-and-blocks) |
| within blocks: |
| |
| - Argument syntax sets a named argument for the containing object. If the |
| attribute has a default value then an explicitly-specified value entirely |
| overrides that default. |
| |
| - Nested block syntax represents a related child object of the container that |
| has its own set of arguments. Where multiple such objects are possible, multiple |
| blocks of the same type can be present. If the nested attributes themselves |
| have default values, they are honored for each nested block separately, |
| merging in with any explicitly-defined arguments. |
| |
| The distinction between these is particularly important for |
| [JSON syntax](/language/syntax/json) |
| because the same primitive JSON constructs (lists and objects) will be |
| interpreted differently depending on whether a particular name is an argument |
| or a nested block type. |
| |
| However, in some cases existing provider features were relying on the |
| conflation of these two concepts in the language of Terraform v0.11 and earlier, |
| using nested block syntax in most cases but using argument syntax to represent |
| explicitly the idea of removing all existing objects of that type, since the |
| absence of any blocks was interpreted as "ignore any existing objects". |
| |
| The information on this page only applies to certain special arguments that |
| were relying on this usage pattern prior to Terraform v0.12. The documentation |
| for each of those features links to this page for details of the special usage |
| patterns that apply. In all other cases, use either argument or nested block |
| syntax as directed by the examples in the documentation for a particular |
| resource type. |
| |
| ## Defining a Fixed Object Collection Value |
| |
| When working with resource type arguments that behave in this way, it is valid |
| and we recommend to use the nested block syntax whenever defining a fixed |
| collection of objects: |
| |
| ```hcl |
| example { |
| foo = "bar" |
| } |
| example { |
| foo = "baz" |
| } |
| ``` |
| |
| The above implicitly specifies a two-element list of objects assigned to the |
| `example` argument, treating it as if it were a nested block type. |
| |
| If you need to explicitly call for zero `example` objects, you must use the |
| argument syntax with an empty list: |
| |
| ```hcl |
| example = [] |
| ``` |
| |
| These two forms cannot be mixed; there cannot be both explicitly zero `example` |
| objects and explicit single `example` blocks declared at the same time. |
| |
| For true nested blocks where this special behavior does not apply, assigning |
| `[]` using argument syntax is not valid. The normal way to specify zero objects |
| of a type is to write no nested blocks at all. |
| |
| ## Arbitrary Expressions with Argument Syntax |
| |
| Although we recommend using block syntax for simple cases for readability, the |
| names that work in this mode _are_ defined as arguments, and so it is possible |
| to use argument syntax to assign arbitrary dynamic expressions to them, as |
| long as the expression has the expected result type: |
| |
| ```hcl |
| example = [ |
| for name in var.names: { |
| foo = name |
| } |
| ] |
| ``` |
| |
| ```hcl |
| # Not recommended, but valid: a constant list-of-objects expression |
| example = [ |
| { |
| foo = "bar" |
| }, |
| { |
| foo = "baz" |
| }, |
| ] |
| ``` |
| |
| Because of the rule that argument declarations like this fully override any |
| default value, when creating a list-of-objects expression directly the usual |
| handling of optional arguments does not apply, so all of the arguments must be |
| assigned a value, even if it's an explicit `null`: |
| |
| ```hcl |
| example = [ |
| { |
| # Cannot omit foo in this case, even though it would be optional in the |
| # nested block syntax. |
| foo = null |
| }, |
| ] |
| ``` |
| |
| If you are writing a reusable module that allows callers to pass in a list of |
| objects to assign to such an argument, you may wish to use the `merge` function |
| to populate any attributes the user didn't explicitly set, in order to give |
| the module user the effect of optional arguments: |
| |
| ```hcl |
| example = [ |
| for ex in var.examples: merge({ |
| foo = null # (or any other suitable default value) |
| }, ex) |
| ] |
| ``` |
| |
| For the arguments that use the attributes-as-blocks usage mode, the above is |
| a better pattern than using |
| [`dynamic` blocks](/language/expressions/dynamic-blocks) |
| because the case where the |
| caller provides an empty list will result in explicitly assigning an empty |
| list value, rather than assigning no value at all and thus retaining and |
| ignoring any existing objects. `dynamic` blocks are required for |
| dynamically-generating _normal_ nested blocks, though. |
| |
| ## In JSON syntax |
| |
| Arguments that use this special mode are specified in JSON syntax always using |
| the [JSON expression mapping](/language/syntax/json#expression-mapping) |
| to produce a list of objects. |
| |
| The interpretation of these values in JSON syntax is, therefore, equivalent |
| to that described under _Arbitrary Expressions with Argument Syntax_ above, |
| but expressed in JSON syntax instead. |
| |
| Due to the ambiguity of the JSON syntax, there is no way to distinguish based |
| on the input alone between argument and nested block usage, so the JSON syntax |
| cannot support the nested block processing mode for these arguments. This is, |
| unfortunately, one necessary concession on the equivalence between native syntax |
| and JSON syntax made pragmatically for compatibility with existing provider |
| design patterns. Providers may phase out such patterns in future major releases. |