github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/website/docs/configuration/attr-as-blocks.html.md (about)

     1  ---
     2  layout: "docs"
     3  page_title: "Attributes as Blocks - Configuration Language"
     4  sidebar_current: "docs-config-attr-as-blocks"
     5  description: |-
     6    For historical reasons, certain arguments within resource blocks can use either
     7    block or attribute syntax.
     8  ---
     9  
    10  # Attributes as Blocks
    11  
    12  -> **Note:** This page is an appendix to the Terraform documentation, and is
    13  outside the normal navigation hierarchy. Most users do not need to know the full
    14  details of the behavior described below.
    15  
    16  ## Summary
    17  
    18  Many resource types use repeatable nested blocks to manage collections of
    19  sub-objects related to the primary resource.
    20  
    21  Rarely, some resource types _also_ support an argument with the same name as a
    22  nested block type, and will purge any sub-objects of that type if that argument
    23  is set to an empty list (`<ATTR> = []`).
    24  
    25  Most users do not need to know any further details of this "nested block or
    26  empty list" behavior. However, read further if you need to:
    27  
    28  - Use Terraform's [JSON syntax](/docs/configuration/syntax-json.html) with this
    29    type of resource.
    30  - Create a reusable module that wraps this type of resource.
    31  
    32  ## Details
    33  
    34  In Terraform v0.12 and later, the language makes a distinction between
    35  [argument syntax and nested block syntax](/docs/configuration/syntax.html#arguments-and-blocks)
    36  within blocks:
    37  
    38  * Argument syntax sets a named argument for the containing object. If the
    39    attribute has a default value then an explicitly-specified value entirely
    40    overrides that default.
    41  
    42  * Nested block syntax represents a related child object of the container that
    43    has its own set of arguments. Where multiple such objects are possible, multiple
    44    blocks of the same type can be present. If the nested attributes themselves
    45    have default values, they are honored for each nested block separately,
    46    merging in with any explicitly-defined arguments.
    47  
    48  The distinction between these is particularly important for
    49  [JSON syntax](/docs/configuration/syntax-json.html)
    50  because the same primitive JSON constructs (lists and objects) will be
    51  interpreted differently depending on whether a particular name is an argument
    52  or a nested block type.
    53  
    54  However, in some cases existing provider features were relying on the
    55  conflation of these two concepts in the language of Terraform v0.11 and earlier,
    56  using nested block syntax in most cases but using argument syntax to represent
    57  explicitly the idea of removing all existing objects of that type, since the
    58  absence of any blocks was interpreted as "ignore any existing objects".
    59  
    60  The information on this page only applies to certain special arguments that
    61  were relying on this usage pattern prior to Terraform v0.12. The documentation
    62  for each of those features links to this page for details of the special usage
    63  patterns that apply. In all other cases, use either argument or nested block
    64  syntax as directed by the examples in the documentation for a particular
    65  resource type.
    66  
    67  ## Defining a Fixed Object Collection Value
    68  
    69  When working with resource type arguments that behave in this way, it is valid
    70  and we recommend to use the nested block syntax whenever defining a fixed
    71  collection of objects:
    72  
    73  ```hcl
    74  example {
    75    foo = "bar"
    76  }
    77  example {
    78    foo = "baz"
    79  }
    80  ```
    81  
    82  The above implicitly specifies a two-element list of objects assigned to the
    83  `example` argument, treating it as if it were a nested block type.
    84  
    85  If you need to explicitly call for zero `example` objects, you must use the
    86  argument syntax with an empty list:
    87  
    88  ```hcl
    89  example = []
    90  ```
    91  
    92  These two forms cannot be mixed; there cannot be both explicitly zero `example`
    93  objects and explicit single `example` blocks declared at the same time.
    94  
    95  For true nested blocks where this special behavior does not apply, assigning
    96  `[]` using argument syntax is not valid. The normal way to specify zero objects
    97  of a type is to write no nested blocks at all.
    98  
    99  ## Arbitrary Expressions with Argument Syntax
   100  
   101  Although we recommend using block syntax for simple cases for readability, the
   102  names that work in this mode _are_ defined as arguments, and so it is possible
   103  to use argument syntax to assign arbitrary dynamic expressions to them, as
   104  long as the expression has the expected result type:
   105  
   106  ```hcl
   107  example = [
   108    for name in var.names: {
   109      foo = name
   110    }
   111  ]
   112  ```
   113  
   114  ```hcl
   115  # Not recommended, but valid: a constant list-of-objects expression
   116  example = [
   117    {
   118      foo = "bar"
   119    },
   120    {
   121      foo = "baz"
   122    },
   123  ]
   124  ```
   125  
   126  Because of the rule that argument declarations like this fully override any
   127  default value, when creating a list-of-objects expression directly the usual
   128  handling of optional arguments does not apply, so all of the arguments must be
   129  assigned a value, even if it's an explicit `null`:
   130  
   131  ```hcl
   132  example = [
   133    {
   134      # Cannot omit foo in this case, even though it would be optional in the
   135      # nested block syntax.
   136      foo = null
   137    },
   138  ]
   139  ```
   140  
   141  If you are writing a reusable module that allows callers to pass in a list of
   142  objects to assign to such an argument, you may wish to use the `merge` function
   143  to populate any attributes the user didn't explicitly set, in order to give
   144  the module user the effect of optional arguments:
   145  
   146  ```hcl
   147  example = [
   148    for ex in var.examples: merge({
   149      foo = null # (or any other suitable default value)
   150    }, ex)
   151  ]
   152  ```
   153  
   154  For the arguments that use the attributes-as-blocks usage mode, the above is
   155  a better pattern than using
   156  [`dynamic` blocks](/docs/configuration/expressions.html#dynamic-blocks)
   157  because the case where the
   158  caller provides an empty list will result in explicitly assigning an empty
   159  list value, rather than assigning no value at all and thus retaining and
   160  ignoring any existing objects. `dynamic` blocks are required for
   161  dynamically-generating _normal_ nested blocks, though.
   162  
   163  ## In JSON syntax
   164  
   165  Arguments that use this special mode are specified in JSON syntax always using
   166  the [JSON expression mapping](/docs/configuration/syntax-json.html#expression-mapping)
   167  to produce a list of objects.
   168  
   169  The interpretation of these values in JSON syntax is, therefore, equivalent
   170  to that described under _Arbitrary Expressions with Argument Syntax_ above,
   171  but expressed in JSON syntax instead.
   172  
   173  Due to the ambiguity of the JSON syntax, there is no way to distinguish based
   174  on the input alone between argument and nested block usage, so the JSON syntax
   175  cannot support the nested block processing mode for these arguments. This is,
   176  unfortunately, one necessary concession on the equivalence between native syntax
   177  and JSON syntax made pragmatically for compatibility with existing provider
   178  design patterns. Providers may phase out such patterns in future major releases.