Generating backend & provider config
Stop copy-pasting boilerplate.
The single biggest boilerplate in multi-module Terraform is the backend block — every root module needs one, and they are nearly identical except for the state key. Terragrunt’s generate and remote_state features produce that config so you write it once. remote_state defines the backend for a unit (and can live in a parent file every unit inherits), and Terragrunt writes the corresponding backend.tf into the generated module at run time.
remote_state {backend = "s3"generate = { path = "backend.tf", if_exists = "overwrite" }config = {bucket = "acme-tf-state"key = "${path_relative_to_include()}/terraform.tfstate" # unique per unitregion = "us-east-1"dynamodb_table = "tf-locks"encrypt = true}}
Generating provider config too
The same generate mechanism produces provider blocks — a common provider.tf (with the right region, assume-role, default tags) injected into every unit, so you configure the provider once instead of in every module. The key trick above is path_relative_to_include(), which gives each unit a distinct state key automatically based on its folder, so you never hand-assign state paths again.
generate "provider" {path = "provider.tf"if_exists = "overwrite"contents = <<EOFprovider "aws" {region = "us-east-1"default_tags { tags = { managed_by = "terragrunt" } }}EOF}