Background

Terragrunt was originally created to support two features that were not available in Terraform: defining remote state configuration in a file (rather than via CLI commands) and locking. As of version 0.9.0, Terraform now supports both of these features natively, so we have made some changes to Terragrunt:

  1. Terragrunt still supports remote state configuration, so you can take advantage of Terragrunt’s interpolation functions.
  2. Terragrunt no longer supports locking.

Migration guide

The following sections outlines the steps you may need to take in order to migrate from Terragrunt <= v0.11.x to Terragrunt 0.12.x. If you are using Terraform <= 0.8.x, see the upgrade guide on the Terraform website Upgrading to Terraform v0.9.

Migration steps include:

Define a backend in your Terraform files

As of Terraform 0.9.0, you must define a backend in your Terraform code (the .tf files). The Terraform guides Upgrading to Terraform v0.9 and Backends: Migrating From 0.8.x and Earlier may be useful to understand backends.

For example, to use S3 as a remote state backend, you will need to add the following to your Terraform code:

# main.tf
terraform {
  # The configuration for this backend will be filled in by Terragrunt
  backend "s3" {}
}

Note that you can leave the configuration of the backend empty and allow Terragrunt to provide that configuration instead. This allows you to keep your remote state configuration more DRY by taking advantage of Terragrunt’s interpolation functions:

# terraform.tfvars
terragrunt = {
  remote_state {
    backend = "s3"
    config {
      bucket  = "my-terraform-state"
      key     = "${path_relative_to_include()}/terraform.tfstate"
      region  = "us-east-1"
      encrypt = true
    }
  }
}

Note: when switching from Terragrunt v0.11.x to v0.12.x, you also need to change the encrypt setting from a string (e.g. "true") to a boolean (e.g. true without the quotes).

Switch from Terragrunt locking to Terraform locking

Remove any lock { ... } blocks from your Terragrunt configurations, as these are no longer supported.

If you were storing remote state in S3 and relying on DynamoDB as a locking mechanism, Terraform now supports that natively. To enable it, simply add the lock_table parameter to your S3 backend configuration. If you configure your S3 backend using Terragrunt, then Terragrunt will automatically create the lock_table for you if that table doesn’t already exist:

# terraform.tfvars
terragrunt = {
  remote_state {
    backend = "s3"
    config {
      bucket  = "my-terraform-state"
      key     = "${path_relative_to_include()}/terraform.tfstate"
      region  = "us-east-1"
      encrypt = true

      # Tell Terraform to do locking using DynamoDB. Terragrunt will automatically
      # create this table for you if it doesn't already exist.
      lock_table = "my-lock-table"
    }
  }
}

NOTE: We recommend using a completely new lock table name and NOT reusing the lock table from older versions of Terragrunt, as that older table had a different structure than what Terraform expects, and Terragrunt will not automatically recreate it.

If you would like Terraform to automatically retry locks like Terragrunt did (this is particularly useful when running Terraform as part of an automated script, such as a CI build), you use an extra_arguments block:

terragrunt = {
  remote_state {
    backend = "s3"
    config {
      bucket  = "my-terraform-state"
      key     = "${path_relative_to_include()}/terraform.tfstate"
      region  = "us-east-1"
      encrypt = true

      # Tell Terraform to do locking using DynamoDB. Terragrunt will automatically
      # create this table for you if it doesn't already exist.
      lock_table = "my-lock-table"
    }
  }

  terraform {
    # Force Terraform to keep trying to acquire a lock for up to 20 minutes
    # if someone else already has the lock.
    extra_arguments "retry_lock" {
      commands = [
        "init",
        "apply",
        "refresh",
        "import",
        "plan",
        "taint",
        "untaint"
      ]

      arguments = [
        "-lock-timeout=20m"
      ]
    }
  }
}

Migrate from .terragrunt to terraform.tfvars

The configuration in a .terragrunt file is identical to that of the terraform.tfvars file, except the terraform.tfvars file requires you to wrap that configuration in a terragrunt = { ... } block.

For example, if this is your .terragrunt file:

include {
  path = "${find_in_parent_folders()}"
}

dependencies {
  paths = ["../vpc", "../mysql", "../redis"]
}

The equivalent terraform.tfvars file is:

terragrunt = {
  include {
    path = "${find_in_parent_folders()}"
  }

  dependencies {
    paths = ["../vpc", "../mysql", "../redis"]
  }
}

To migrate, all you need to do is:

  1. Copy all the contents of the .terragrunt file.
  2. Paste those contents into a terragrunt = { ... } block in a terraform.tfvars file.
  3. Delete the .terragrunt file.