When you have set up your infrastructure with Terraform and then do any change to the user_data of a EC2 instance, Terraform will detect the change and generally do a force-replacement of the instance. In the planning stage this could look something like this:

  # aws_instance.web_backend must be replaced
-/+ resource "aws_instance" "web_backend" {
      [...]
      ~ user_data                            = "1c4e236bd5dec74fecc99d3a3d57679b9b12a927" -> "f8d9add08d4ead74d44af35452c6070dbfcb1576" # forces replacement
      + user_data_base64                     = (known after apply)
      [...]

So what can you do when you want to make changes to user_data but don’t want to destroy your instance and create a new one?

For this case there is a lifecycle meta-argument in which you can customize certain resource behaviours.

The argument we are looking for is ignore_changes. You can declare this to tell Terraform to ignore changes to certain attributes of a resource that occur after its creation.

The user_data of a EC2 instance is just an example here – you may use it for any other data as well. But sticking with this example, let’s see how our modified EC2 instance could look like:

resource "aws_instance" "web_backend" {
  [...]
  user_data = local.ec2_user_data

  # don't force-recreate instance if only user data changes
  lifecycle {
    ignore_changes = [user_data]
  }
}

Making changes to user_data and then running terraform plan again, you will see that Terraform won’t pick up the change and thus won’t tell you that the resource must be replaced.