github.com/hugorut/terraform@v1.1.3/website/docs/language/upgrade-guides/0-12.mdx (about)

     1  ---
     2  page_title: Upgrading to Terraform 0.12
     3  description: Upgrading to Terraform v0.12
     4  ---
     5  
     6  # Upgrading to Terraform v0.12
     7  
     8  [Terraform v0.12 is a major release](https://hashicorp.com/blog/terraform-0-1-2-preview)
     9  focused on configuration language improvements and thus includes some
    10  changes that you'll need to consider when upgrading. The goal of this guide is
    11  to cover the most common upgrade concerns and issues.
    12  
    13  For most users, upgrading configuration should be completely automatic. Some
    14  simple configurations will require no changes at all, and most other
    15  configurations can be prepared by running
    16  [the automatic upgrade tool](/cli/commands/0.12upgrade). Please read on
    17  for more information and recommendations on the upgrade process.
    18  
    19  -> If you are a developer maintaining a provider plugin, please see
    20  [the documentation on 0.12 compatibility for providers](/plugin/sdkv2/guides/terraform-0.12-compatibility)
    21  to learn more about the changes that are required.
    22  
    23  ## Upgrade to Terraform 0.11 first
    24  
    25  We strongly recommend completing an upgrade to the latest Terraform v0.11
    26  release first. This will give you an opportunity to address any changes
    27  required for the previous major version upgrades separately, rather than
    28  making multiple changes at once.
    29  
    30  In particular, if you are upgrading from a Terraform version prior to v0.9,
    31  you _must_ first [upgrade to Terraform v0.9](/language/upgrade-guides/0-9) and
    32  switch to initializing with `terraform init`, because v0.12 no longer includes
    33  the functionality for automatically migrating from the legacy remote state
    34  mechanism.
    35  
    36  This guide focuses on changes from v0.11 to v0.12. Each previous major release
    37  has its own upgrade guide, so please consult the other guides (available in the
    38  navigation) to upgrade step-by-step to v0.11 first.
    39  
    40  Terraform v0.11.14 (and any subsequent v0.11 releases) also include some
    41  additional functionality to help smooth the upgrade, which we will use later
    42  in this guide.
    43  
    44  Prior versions of Terraform are available from
    45  [the releases server](https://releases.hashicorp.com/terraform/).
    46  
    47  ## Pre-upgrade Checklist
    48  
    49  Terraform v0.11.14 introduced a temporary helper command
    50  `terraform 0.12checklist`, which analyzes your configuration to detect any
    51  required steps that will be easier to perform before upgrading.
    52  
    53  To use it, first upgrade to [Terraform v0.11.14](https://releases.hashicorp.com/terraform/0.11.14/).
    54  Then, perform the following steps:
    55  
    56  * `terraform init` to ensure your working directory is fully initialized and
    57    all required plugins are installed and selected.
    58  * `terraform apply` to ensure that your real infrastructure and Terraform
    59    state are consistent with the current configuration. The instructions
    60    produced by the checklist command assume that configuration and state are
    61    synchronized.
    62  * `terraform 0.12checklist` to see if there are any pre-upgrade steps in the
    63    checklist.
    64  
    65  If all is well, the final command will produce a message like this:
    66  
    67  ```
    68  Looks good! We did not detect any problems that ought to be
    69  addressed before upgrading to Terraform v0.12
    70  
    71  This tool is not perfect though, so please check the v0.12 upgrade
    72  guide for additional guidance, and for next steps:
    73      https://www.terraform.io/upgrade-guides/0-12.html
    74  ```
    75  
    76  As the message suggests, the next step in that case is to read the remainder
    77  of this page to prepare for and carry out the upgrade.
    78  
    79  However, the checklist command may instead produce a list of one or more tasks
    80  that we recommend you perform before upgrading to Terraform 0.12, because they
    81  are easier to perform with a fully-functional Terraform 0.11 than with a
    82  Terraform 0.12 that has encountered compatibility problems.
    83  
    84  The tasks it may suggest you perform could include:
    85  
    86  * Upgrading any provider versions that are not compatible with Terraform v0.12.
    87    We recommend upgrading to the latest version of each provider before upgrading
    88    because that will avoid changing many things in one step.
    89  * Renaming any resources or provider aliases that have names that start with
    90    digits, because that is no longer valid in Terraform 0.12.
    91  * Upgrading any external modules the configuration uses which themselves have
    92    the above problems.
    93  
    94  In each case, the tool will give some direction on how to perform the task it
    95  is suggesting.
    96  
    97  The output from `terraform 0.12checklist` is in Markdown format so that it can
    98  easily be pasted into a Markdown-compatible issue tracker, should you want
    99  to track the necessary tasks or share the work with other team members.
   100  
   101  After all of the tasks are complete, run `terraform 0.12checklist` one more time
   102  to verify that everything is complete. If so, continue reading the following
   103  sections to complete the upgrade!
   104  
   105  ### Addendum: Invalid module names
   106  
   107  There is one additional pre-upgrade checklist item that the Terraform team did
   108  not become aware of until after the release of Terraform v0.11.14, and thus
   109  cannot be detected automatically by the checklist tool: renaming modules which
   110  have names that start with digits.
   111  
   112  Terraform 0.11 inadvertently tolerated leading-digit names for modules as a
   113  result of a validation bug, but Terraform 0.12 has corrected that bug and will
   114  reject such module names. Unfortunately, module names are also recorded in
   115  state snapshots and so a state snapshot created for a configuration with an
   116  invalid module name will itself be invalid as far as Terraform 0.12 is
   117  concerned.
   118  
   119  You can address this in a similar way to what the checklist tool suggests for
   120  invalid resource names and provider aliases:
   121  
   122  * Rename the module in your configuration.
   123  * Use `terraform state mv module.old module.new` _in Terraform 0.11.14_ to
   124    update the state to use the new name instead of the old name.
   125  
   126  As with all of the pre-upgrade checklist items, be sure to run `terraform apply`
   127  once more before upgrading in order to ensure that the latest state snapshot is
   128  synchronized with the latest configuration.
   129  
   130  ## Upgrading to Terraform 0.12
   131  
   132  Before switching to Terraform 0.12, we recommend using Terraform v0.11.14 (or
   133  any later v0.11 release) to perform one last `terraform init` and
   134  `terraform apply` to ensure that everything is initialized and synchronized.
   135  
   136  Once `terraform apply` shows no changes pending, switch over to a Terraform
   137  v0.12 release and run `terraform init` again to upgrade the working directory
   138  metadata to v0.12 format. (Once you've done this, you'll need to delete the
   139  `.terraform` directory if you wish to return to Terraform v0.11, but no
   140  real infrastructure or persisted state will be upgraded yet.)
   141  
   142  It is possible that your configuration may be using configuration constructs
   143  that are not Terraform v0.12 compatible and thus require upgrade. In that case,
   144  `terraform init` will produce the following message:
   145  
   146  ```
   147  Terraform has initialized, but configuration upgrades may be needed.
   148  
   149  Terraform found syntax errors in the configuration that prevented full
   150  initialization. If you've recently upgraded to Terraform v0.12, this may be
   151  because your configuration uses syntax constructs that are no longer valid,
   152  and so must be updated before full initialization is possible.
   153  
   154  Terraform has installed the required providers to support the configuration
   155  upgrade process. To begin upgrading your configuration, run the following:
   156      terraform 0.12upgrade
   157  
   158  To see the full set of errors that led to this message, run:
   159      terraform validate
   160  ```
   161  
   162  As mentioned in the message, Terraform has partially initialized the directory
   163  just enough to perform the configuration upgrade process, which is described
   164  in the following section.
   165  
   166  We recommend running the configuration upgrade tool even if you do not see
   167  the above message, because it may detect and fix constructs that are
   168  syntactically correct but still need some changes to work as expected with
   169  Terraform v0.12.
   170  
   171  ## Upgrading Terraform configuration
   172  
   173  Terraform v0.12 includes a new command `terraform 0.12upgrade` that will
   174  read the configuration files for a module written for Terraform 0.11 and
   175  update them in-place to use the cleaner Terraform 0.12 syntax and also
   176  adjust for use of features that have changed behavior in the 0.12 Terraform
   177  language.
   178  
   179  Simple configuration files are likely to be understood by Terraform 0.12 as-is,
   180  because the language is still broadly compatible, but we recommend that everyone
   181  run the upgrade tool nonetheless. Even if your configuration is already
   182  compatible, the tool will update your configuration to use the cleaner syntax
   183  available in Terraform 0.12, which should improve readability.
   184  
   185  To run the command, first make sure that your local working directory is synced
   186  with your version control system so that there are no changes outstanding. This
   187  will make it easier to review the changes that the upgrade tool is proposing,
   188  using the diff feature of your version control system.
   189  
   190  With a fully-initialized working directory (all necessary providers and child
   191  modules installed), run `terraform 0.12upgrade` to begin the process. By default
   192  it will print some information about what it is about to do and prompt for
   193  confirmation:
   194  
   195  ```
   196  This command will rewrite the configuration files in the given directory so
   197  that they use the new syntax features from Terraform v0.12, and will identify
   198  any constructs that may need to be adjusted for correct operation with
   199  Terraform v0.12.
   200  
   201  We recommend using this command in a clean version control work tree, so that
   202  you can easily see the proposed changes as a diff against the latest commit.
   203  If you have uncommitted changes already present, we recommend aborting this
   204  command and dealing with them before running this command again.
   205  
   206  Would you like to upgrade the module in the current directory?
   207  ```
   208  
   209  If you answer yes, the `.tf` and `.tfvars` files in your current working
   210  directory will be rewritten in-place.
   211  
   212  The upgrade tool may also print out warnings about constructs it wasn't able to
   213  migrate fully automatically; in that case, it will also emit comments into the
   214  rewritten source files containing the special marker `TF-UPGRADE-TODO`, as
   215  a prompt for a decision you'll need to make to complete the upgrade.
   216  
   217  Once the upgrade tool has successfully completed and you've resolved any
   218  `TF-UPGRADE-TODO` prompts, use your version control tool to review the proposed
   219  changes and then run `terraform plan` to see the effect of those changes.
   220  
   221  In most cases, `terraform plan` should report that no changes are required,
   222  because the updated configuration is equivalent to before.
   223  
   224  The remaining sections below describe both some common changes that the upgrade
   225  tool is able to make automatically, and some other upgrade situations that
   226  the configuration tool may not be able to fully resolve. If you encounter
   227  any errors during the upgrade or during the subsequent `terraform plan`, the
   228  sections below may give some additional context for how to proceed.
   229  
   230  Once you're happy with the updated configuration, commit it to version control
   231  in the usual way and apply it with Terraform 0.12.
   232  
   233  ### Remote state references
   234  
   235  The `terraform_remote_state` data source has changed slightly for the v0.12
   236  release to make all of the remote state outputs available as a single map
   237  value, rather than as top-level attributes as in previous releases.
   238  
   239  In previous releases, a reference to a `vpc_id` output exported by the remote
   240  state data source might have looked like this:
   241  
   242  ```hcl
   243  data.terraform_remote_state.vpc.vpc_id
   244  ```
   245  
   246  This value must now be accessed via the new `outputs` attribute:
   247  
   248  ```hcl
   249  data.terraform_remote_state.vpc.outputs.vpc_id
   250  ```
   251  
   252  The upgrade tool will rewrite remote state references automatically to include
   253  the additional `outputs` attribute.
   254  
   255  Where appropriate, you can also access the outputs attribute directly to
   256  work with the whole map as a single value:
   257  
   258  ```hcl
   259  data.terraform_remote_state.vpc.outputs
   260  ```
   261  
   262  Another consideration for `terraform_remote_state` is that this data source must
   263  be able to parse the latest state snapshot for a separate Terraform
   264  configuration that may have been updated by a newer version of Terraform.
   265  To provide flexibility when upgrading decomposed environments that use
   266  `terraform_remote_state`, Terraform v0.11.14 introduced support for reading
   267  outputs from the Terraform v0.12 state format, so if you upgrade all of your
   268  configurations to Terraform v0.11.14 first you can then perform v0.12 upgrades
   269  of individual configurations in any order, without breaking
   270  `terraform_remote_state` usage.
   271  
   272  Note that the `config` block should now be in the form of an assignment with the `=` sign:
   273  
   274  ```hcl
   275  data "terraform_remote_state" "default" {
   276    backend = "gcs"
   277    config = {
   278      bucket = "..."
   279    }
   280  }
   281  ```
   282  
   283  ### Attributes vs. blocks
   284  
   285  Terraform resource configurations consist of both arguments that set
   286  individual properties of the main object being described, and nested blocks
   287  which declare zero or more other objects that are modeled as being part of
   288  their parent. For example:
   289  
   290  ```hcl
   291  resource "aws_instance" "example" {
   292    instance_type = "t2.micro"
   293    ami           = "ami-abcd1234"
   294  
   295    tags = {
   296      Name = "example instance"
   297    }
   298  
   299    ebs_block_device {
   300      device_name = "sda2"
   301      volume_type = "gp2"
   302      volume_size = 24
   303    }
   304  }
   305  ```
   306  
   307  In the above resource, `instance_type`, `ami`, and `tags` are both direct
   308  arguments of the `aws_instance` resource, while `ebs_block_device` describes
   309  a separate EBS block device object that is connected to the parent instance.
   310  
   311  Due to the design of the configuration language decoder in Terraform v0.11 and
   312  earlier, it was in many cases possible to interchange the argument syntax
   313  (with `=`) and the block syntax (with just braces) when dealing with map
   314  arguments vs. nested blocks. However, this led to some subtle bugs and
   315  limitations, so Terraform v0.12 now requires consistent usage of argument
   316  syntax for arguments and nested block syntax for nested blocks.
   317  
   318  In return for this new strictness, Terraform v0.12 now allows map keys to be
   319  set dynamically from expressions, which is a long-requested feature. The
   320  main difference between a map attribute and a nested block is that a map
   321  attribute will usually have user-defined keys, like we see in the `tags`
   322  example above, while a nested block always has a fixed set of supported
   323  arguments defined by the resource type schema, which Terraform will validate.
   324  
   325  The configuration upgrade tool uses the provider's schema to recognize the
   326  nature of each construct and will select the right syntax automatically. For
   327  most simple usage, this will just involve adding or removing the equals sign
   328  as appropriate.
   329  
   330  A more complicated scenario is where users found that they could exploit this
   331  flexibility to -- with some caveats -- dynamically generate nested blocks even
   332  though this wasn't intentionally allowed:
   333  
   334  ```hcl
   335    # Example of no-longer-supported workaround from 0.11 and earlier
   336    ebs_block_device = "${concat(map("device_name", "sda4"), var.extra_block_devices)}"
   337  ```
   338  
   339  Terraform v0.12 now includes a first-class feature for dynamically generating
   340  nested blocks using expressions, using the special `dynamic` block type. The
   341  above can now be written like this, separating the static block device from
   342  the dynamic ones:
   343  
   344  ```hcl
   345    ebs_block_device {
   346      device_name = "sda4"
   347    }
   348    dynamic "ebs_block_device" {
   349      for_each = var.extra_block_devices
   350      content {
   351        device_name = ebs_block_device.value.device_name
   352        volume_type = ebs_block_device.value.volume_type
   353        volume_size = ebs_block_device.value.volume_size
   354      }
   355    }
   356  ```
   357  
   358  The configuration upgrade tool will detect use of the above workaround and
   359  rewrite it as a `dynamic` block, but it may make non-ideal decisions for how to
   360  flatten your expression down into static vs. dynamic blocks, so we recommend
   361  reviewing the generated `dynamic` blocks to see if any simplifications are
   362  possible.
   363  
   364  Terraform v0.12 now also requires that each argument be set only once within
   365  a particular block, whereas before Terraform would either take the last
   366  definition or, in some cases, attempt to merge together multiple definitions
   367  into a list. The upgrade tool does not remove or attempt to consolidate
   368  any existing duplicate arguments, but other commands like `terraform validate`
   369  will detect and report these after upgrading.
   370  
   371  ### Integer vs. Float Number Types
   372  
   373  From Terraform v0.12, the Terraform language no longer distinguishes between
   374  integer and float types, instead just having a single "number" type that can
   375  represent high-precision floating point numbers. This new type can represent
   376  any value that could be represented before, plus many new values due to the
   377  expanded precision.
   378  
   379  In most cases this change should not cause any significant behavior change, but
   380  please note that in particular the behavior of the division operator is now
   381  different: it _always_ performs floating point division, whereas before it
   382  would sometimes perform integer division by attempting to infer intent from
   383  the argument types.
   384  
   385  If you are relying on integer division behavior in your configuration, please
   386  use the `floor` function to obtain the previous result. A common place this
   387  would arise is in index operations, where the index is computed by division:
   388  
   389  ```hcl
   390    example = var.items[floor(count.index / var.any_number)]
   391  ```
   392  
   393  Using a fractional number to index a list will produce an error telling you
   394  that this is not allowed, serving as a prompt to add `floor`:
   395  
   396  ```
   397  Error: Invalid index
   398  
   399  The given key does not identify an element in this collection value: indexing a
   400  sequence requires a whole number, but the given index (0.5) has a fractional
   401  part.
   402  ```
   403  
   404  Unfortunately the automatic upgrade tool cannot apply a fix for this case
   405  because it does not have enough information to know if floating point or integer
   406  division was intended by the configuration author, so this change must be made
   407  manually where needed.
   408  
   409  ### Referring to List Variables
   410  
   411  In early versions of Terraform, before list support became first-class, we
   412  required using seemingly-redundant list brackets around a single expression
   413  in order to hint to the language interpreter that a list interpretation was
   414  desired:
   415  
   416  ```hcl
   417    # Example for older versions of Terraform; not valid for v0.12
   418    example = ["${var.any_list}"]
   419  ```
   420  
   421  This strange requirement was subsequently lifted after the introduction of
   422  first-class list support, but we retained compatibility with this older usage
   423  for a transitional period by including some fixup logic that would detect when
   424  list brackets contain list expressions and automatically flatten to a single
   425  list.
   426  
   427  As part of implementing the first-class expressions support for v0.12, we needed
   428  to finally remove that backward-compatibility mechanism to avoid ambiguity
   429  in the language, so an expression like the above will now produce a list of
   430  lists and thus produce a type checking error for any argument that was expecting
   431  a list of some other type.
   432  
   433  The upgrade tool is able to recognize most simple usage of this pattern and
   434  rewrite automatically to just refer to the list directly:
   435  
   436  ```hcl
   437    example = var.any_list
   438  ```
   439  
   440  However, an unintended side-effect of this compatibility mechanism was to
   441  also flatten mixed lists of single-value and list expressions into a single
   442  list automatically. We didn't intend for this to be a part of the language, but
   443  in retrospect it was an obvious consequence of how the compatibility mechanism
   444  was implemented. If you have expressions in your modules that produce a list
   445  of strings by using list brackets with a mixture of string and list-of-string
   446  sub-expressions, you will need to rewrite this to explicitly use
   447  [the `flatten` function](/language/functions/flatten)
   448  to make the special treatment more obvious to the reader:
   449  
   450  ```hcl
   451    example = flatten([
   452      "single string",
   453      var.any_list,
   454    ])
   455  ```
   456  
   457  The configuration upgrade tool unfortunately cannot make this change
   458  automatically, because it doesn't have enough information to know for certain
   459  which interpretation was intended for a given list.
   460  
   461  For complex examples that the upgrade tool is not able to adjust automatically,
   462  subsequent Terraform operations may produce an error message like the following:
   463  
   464  ```
   465  Error: Incorrect attribute value type
   466  
   467    on redundant-list-brackets.tf line 9, in resource "aws_security_group" "foo":
   468     9:     cidr_blocks = ["${var.cidr_blocks}"]
   469  
   470  Inappropriate value for attribute "cidr_blocks": element 0: string required.
   471  ```
   472  
   473  This message is reporting that Terraform has understood this expression as a
   474  list of lists, and therefore element zero is a list rather than a string. To
   475  fix the error, remove the redundant list brackets and possibly add a
   476  `flatten` function call as described above, for more complex cases.
   477  
   478  ### Reserved Variable Names
   479  
   480  In preparation for new features planned for future releases, Terraform 0.12
   481  reserves some additional names that can no longer be used as input variable
   482  names for modules. These reserved names are:
   483  
   484  * `count`
   485  * `depends_on`
   486  * `for_each`
   487  * `lifecycle`
   488  * `providers`
   489  * `source`
   490  
   491  When any of these names is used as the label of a `variable` block, Terraform
   492  will now generate the following error:
   493  
   494  ```
   495  Error: Invalid variable name
   496  
   497    on reserved-variable-names.tf line 2, in variable "count":
   498     2: variable "count" {
   499  
   500  The variable name "count" is reserved due to its special meaning inside module
   501  blocks.
   502  ```
   503  
   504  The upgrade tool cannot automatically adjust for these reserved names, because
   505  it does not know what new name would be more appropriate. To proceed, you must
   506  unfortunately rename these input variables and make a new major release of
   507  the module in question, since renaming input variables is a breaking change.
   508  
   509  ### Type Constraints on Variables
   510  
   511  In Terraform v0.11, variables were documented as accepting only strings, lists
   512  of strings, and maps of strings. However, in practice Terraform permitted
   513  lists of lists and lists of maps and other nested structures in some cases,
   514  even though it was then generally inconvenient to work with those values
   515  elsewhere in the module due to limitations of the index syntax, `element`
   516  function, and `lookup` function.
   517  
   518  Terraform now allows various [type constraints](/language/expressions/type-constraints)
   519  to be specified, as part of the language's new type system and generalized
   520  functions and operators. However, because lists and maps of non-string values
   521  were not officially supported in 0.11, existing configurations do not have
   522  enough information for the upgrade tool to know what element type was intended.
   523  It will therefore assume that lists and maps are of strings as documented,
   524  which will be incorrect for configurations using more complex structures. The
   525  result will be one of the following error messages:
   526  
   527  ```
   528  Error: Invalid default value for variable
   529  
   530    on child_module/example.tf line 4, in variable "example":
   531     4:   default = [
   532     5:     {
   533     6:       "foo" = "bar"
   534     7:     },
   535     8:   ]
   536  
   537  This default value is not compatible with the variable's type constraint:
   538  element 0: string required.
   539  ```
   540  
   541  ```
   542  Error: Invalid value for module argument
   543  
   544    on variables-incorrect-elem-type.tf line 4, in module "child":
   545     4:   example = [
   546     5:     {
   547     6:       "foo" = "bar"
   548     7:     },
   549     8:   ]
   550  
   551  The given value is not suitable for child module variable "example" defined at
   552  child/child.tf:1,1-19: element 0: string required.
   553  ```
   554  
   555  To fix this, change the `type` argument from `list(string)` or `map(string)`
   556  to a more appropriate [type constraint](/language/expressions/type-constraints).
   557  
   558  If you're not sure what type constraint to use yet, another option is to
   559  use the type constraint `any`, which will effectively disable validation and
   560  allow any value. We recommend using specific types where possible, but selecting
   561  `any` during upgrade may be preferable, so that the work to select and define
   562  a more precise type can be saved for a later change at your leisure, once
   563  upgrading is complete.
   564  
   565  ### Working with `count` on resources
   566  
   567  The `count` feature allows declaration of multiple instances of a particular
   568  resource constructed from the same configuration. In Terraform v0.11, any
   569  use of `count` would generally lead to referring to the resource in question
   570  using the "splat expression" syntax elsewhere in the configuration:
   571  
   572  ```
   573  aws_instance.example.*.id[0]
   574  ```
   575  
   576  Because `aws_instance.example` itself was not directly referencable in
   577  Terraform v0.11, the expression system allowed some flexibility in how such
   578  expressions were resolved. For example, Terraform would treat
   579  `aws_instance.example.id` as an alias for `aws_instance.example.*.id[0]`.
   580  
   581  Terraform v0.12 allows referring to an entire resource as an object value,
   582  but that required making a decision on what type of value is returned by
   583  `aws_instance.example`. The new rules are as follows:
   584  
   585  * For resources where `count` is _not_ set, a reference like
   586    `aws_instance.example` returns a single object, whose attributes can be
   587    accessed in the usual way, like `aws_instance.example.id`.
   588  
   589  * For resources where `count` _is_ set -- even if the expression evaluates to
   590    `1` -- `aws_instance.example` returns a list of objects whose length is
   591    decided by the count. In this case `aws_instance.example.id` is an error,
   592    and must instead be written as `aws_instance.example[0].id` to access
   593    one of the objects before retrieving its `id` attribute value.
   594  
   595  The splat syntax is still available and will still be useful in situations
   596  where a list result is needed, but we recommend updating expressions like
   597  `aws_instance.example.*.id[count.index]` to instead be
   598  `aws_instance.example[count.index].id`, which should be easier to read and
   599  understand for those who are familiar with other languages.
   600  
   601  Another consequence of the new handling of `count` is that you can use the
   602  `length` function directly with references to resources that have `count` set:
   603  
   604  ```
   605  length(aws_instance.example)
   606  ```
   607  
   608  This replaces the v0.11 special case of `aws_instance.example.count`, which
   609  can no longer be supported due to `aws_instance.example` being a list.
   610  
   611  The upgrade tool will automatically detect references that are inconsistent
   612  with the `count` setting on the target resource and rewrite them to use the
   613  new syntax. The upgrade tool will _not_ rewrite usage of splat syntax to
   614  direct index syntax, because the old splat syntax form is still compatible.
   615  
   616  Another `count`-related change is that Terraform now requires `count` to be
   617  assigned a numeric value, and will not automatically convert a boolean value
   618  to a number in the interests of clarity. If you wish to use a boolean value
   619  to activate or deactivate a particular resource, use the conditional operator
   620  to show clearly how the boolean value maps to a number value:
   621  
   622  ```hcl
   623    count = var.enabled ? 1 : 0
   624  ```
   625  
   626  ### First-class expressions
   627  
   628  Terraform v0.11 and earlier allowed expressions only within interpolation
   629  sequences, like `"${var.example}"`. Because expressions are such an important
   630  part of Terraform -- they are the means by which we connect the attributes of
   631  one resource to the configuration of another -- Terraform v0.12 now allows
   632  you to use expressions directly when defining most attributes.
   633  
   634  ```
   635    ami = var.ami
   636  ```
   637  
   638  The generalization of expression handling also has some other benefits. For
   639  example, it's now possible to directly construct lists and maps within
   640  expressions using the normal syntax, whereas in Terraform v0.11 we required
   641  using the `list` and `map` functions:
   642  
   643  ```
   644    # Old 0.11 example
   645    tags = "${merge(map("Name", "example"), var.common_tags)}"
   646  
   647    # Updated 0.12 example
   648    tags = merge({ Name = "example" }, var.common_tags)
   649  ```
   650  
   651  The automatic upgrade tool will perform rewrites like these automatically,
   652  making expressions easier to read and understand.
   653  
   654  ### Default settings in `connection` blocks
   655  
   656  Terraform v0.11 and earlier allowed providers to pre-populate certain arguments
   657  in a `connection` block for use with remote provisioners. Several resource
   658  type implementations use this to pre-populate `type` as `"ssh"` and `host`
   659  as one of the IP addresses of the compute instance being created.
   660  
   661  While that feature was convenient in some cases, we found that in practice it
   662  was hard for users to predict how it would behave, since each provider had its
   663  own rules for whether to prefer public vs. private IP addresses, which network
   664  interface to use, whether to use IPv4 or IPv6, etc.
   665  
   666  It also violated our design principle of "explicit is better than implicit": we
   667  think it's important that someone who is unfamiliar with a particular Terraform
   668  configuration (or with Terraform itself) to be able to read the configuration
   669  and make a good guess as to what it will achieve, and the default connection
   670  settings feature left an important detail unstated: how do the provisioners
   671  access the host?
   672  
   673  With this in mind, Terraform v0.12 no longer performs any automatic population
   674  of `connection` blocks. Instead, if you are using any remote provisioners you
   675  should explicitly set the connection type and the hostname to connect to:
   676  
   677  ```hcl
   678    connection {
   679      type = "ssh"
   680      host = self.public_ip
   681      # ...
   682    }
   683  ```
   684  
   685  The automatic upgrade tool will detect existing `connection` blocks that are
   686  lacking these settings within resource types that are known to have previously
   687  set defaults, and it will write out an expression that approximates whatever
   688  selection logic the provider was previously doing in its own implementation.
   689  
   690  Unfortunately in some cases the provider did not export the result of the
   691  possibly-rather-complex host selection expression as a single attribute, and so
   692  for some resource types the generated `host` expression will be quite
   693  complicated. We recommend reviewing these and replacing them with a simpler
   694  expression where possible, since you will often know better than Terraform does
   695  which of the instance IP addresses are likely to be accessible from the host
   696  where Terraform is running.
   697  
   698  ### Equality operations must be valid on value and type
   699  
   700  In 0.11, `"1"` would compare truthfully against `1`, however, in 0.12,
   701  values must be equal on both value and type in order to be true. That is, in 0.11
   702  you would see:
   703  
   704  ```
   705  > "1" == 1
   706  true
   707  ```
   708  
   709  and in 0.12:
   710  
   711  ```
   712  > "1" == 1
   713  false
   714  ```
   715  
   716  This means special care should be taken if you have any conditionals comparing to say,
   717  `count.index` where you were previously expecting it to be a string, when it is now a number.
   718  
   719  This is a scenario where you would need to update existing 0.11 code to work as you expect in 0.12:
   720  
   721  ```
   722  resource "server_instance" "app" {
   723      server_status = "${count.index == local.prod_index ? "production" : "standby"}"
   724    }
   725  }
   726  
   727  locals {
   728    # when migrating to 0.12, be sure to change this value to a number
   729    # to ensure expected behavior
   730    prod_index = "0"
   731  }
   732  ```
   733  
   734  Also take care that if you have a variable that is a number, but defined as a string,
   735  the upgrade tool will not change it to a number, so take care to inspect your code:
   736  
   737  ```
   738  locals {
   739    some_count = "3" # will not be changed to a number after config upgrade
   740  }
   741  ```
   742  
   743  ## Upgrades for reusable modules
   744  
   745  If you are making upgrades to a reusable module that is consumed by many
   746  different configurations, you may need to take care with the timing of your
   747  upgrade and of how you publish it.
   748  
   749  We strongly recommend using module versioning, either via a Terraform registry
   750  or via version control arguments in your module source addresses, to pin
   751  existing references to the old version of the module and then publish the
   752  upgraded version under a new version number. If you are using semantic
   753  versioning, such as in a Terraform registry, the updates made by the upgrade
   754  tool should be considered a breaking change and published as a new major
   755  version.
   756  
   757  The migration tool will automatically add a `>= 0.12.0` Terraform version
   758  constraint to indicate that the module has been upgraded to use v0.12-only
   759  features. By using version constraints, users can gradually update their callers
   760  to use the newly-upgraded version as they begin to use Terraform v0.12 with
   761  those modules.
   762  
   763  For simpler modules it may be possible to carefully adapt them to be both
   764  0.11 and 0.12 compatible at the same time, by following the upgrade notes in
   765  earlier sections and avoiding any v0.12-only features. However, for any module
   766  using a undocumented workarounds for v0.11 limitations it is unlikely to be
   767  possible to both update it for Terraform v0.12 and retain v0.11 compatibility
   768  at the same time, because those undocumented workarounds have been replaced
   769  with new features in Terraform v0.12.
   770  
   771  ## Map variables no longer merge when overridden
   772  
   773  In prior versions of Terraform, a variable of type `"map"` had a special
   774  behavior where any value provided via mechanisms such as the `-var` command
   775  line option would be keywise-merged with any default value associated with
   776  the variable. This was useful in early versions of Terraform that lacked
   777  mechanisms for doing such merging explicitly, but since Terraform v0.10
   778  introduced the concept of local values we consider it preferable to perform
   779  such merges manually so that they are explicit in configuration:
   780  
   781  ```
   782  variable "example_map" {
   783    type = map(string)
   784    default = {}
   785  }
   786  
   787  locals {
   788    default_map_keys = {
   789      "a" = "b"
   790    }
   791    merged_map_keys = merge(local.default_map_keys, var.example_map)
   792  }
   793  ```
   794  
   795  In order to improve the consistency of variable handling across types, the
   796  map variable merging behavior is removed in Terraform v0.12. Because this
   797  mechanism was driven by command line options rather than configuration, the
   798  automatic upgrade tool cannot automatically handle it. If you are relying on
   799  the merging feature, you must reorganize your configuration to use explicit
   800  merging like in the above example, or else your default map value will be
   801  entirely overridden by any explicitly-set value.
   802  
   803  ## Upgrading `remote` Backend Configuration
   804  
   805  Terraform Cloud and Terraform Enterprise users will need
   806  to run `terraform init -reconfigure` to upgrade to Terraform 0.12.
   807  
   808  Terraform provides a message stating that `terraform init` is required; while
   809  there is no harm in running this command, the next error message will clarify
   810  that `terraform init -reconfigure` is required.
   811  
   812  ## Upgrading Sentinel policies
   813  
   814  The Terraform Sentinel imports have been updated to work with Terraform 0.12.
   815  Care has been taken to ensure that the API is as backwards compatible as
   816  possible and most policies will continue to work without modification. However,
   817  there are some important changes and certain policies will need to modified.
   818  
   819  More information on the changes can be found in our page on [using Sentinel with
   820  Terraform 0.12](/cloud-docs/sentinel/sentinel-tf-012).
   821  
   822  It's strongly advised that you test your Sentinel policies after upgrading to
   823  Terraform 0.12 to ensure they continue to work as expected. [Mock
   824  generation](/cloud-docs/sentinel/mock) has also been updated to
   825  produce mock data for the Sentinel imports as they appear in Terraform 0.12.
   826  
   827  For more information on testing a policy with 0.11 and 0.12 at the same time,
   828  see the section on [testing a policy with 0.11 and 0.12
   829  simultaneously](/cloud-docs/sentinel/sentinel-tf-012#testing-a-policy-with-0-11-and-0-12-simultaneously).