CoursesTerragruntIntermediate

DRY remote state

One backend block for the whole repo.

Advanced14 min · lesson 5 of 12

DRY remote state is Terragrunt’s headline win. Instead of a backend block in every unit, you put one remote_state definition in a root terragrunt.hcl and have every child unit include it. Each unit then gets the same backend with a state key derived from its path — so thirty units share one backend definition and each still writes to its own isolated state file. Change the backend once and every unit follows.

root.hcl (repo root)
remote_state {
backend = "s3"
generate = { path = "backend.tf", if_exists = "overwrite" }
config = {
bucket = "acme-tf-state"
key = "${path_relative_to_include()}/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "tf-locks"
encrypt = true
}
}
live/prod/vpc/terragrunt.hcl
include "root" {
path = find_in_parent_folders("root.hcl") # inherit the backend + more
}
terraform { source = "git::...//vpc?ref=v1.4.0" }
inputs = { cidr_block = "10.20.0.0/16" }

One backend, isolated state per unit

The combination of a shared remote_state and path_relative_to_include() gives you the best of both: one place defines the backend (DRY), and every unit gets a unique state key from its folder structure (isolation). Small isolated states mean a mistake in the app unit cannot corrupt the vpc unit’s state, plans stay fast, and locking is per-unit. This structure is why Terragrunt scales to hundreds of state files sanely.

The state key must be unique per unit
If two units resolve to the same backend key they share (and clobber) one state file — a serious corruption risk. path_relative_to_include() derives the key from the folder path, so keep your directory structure unique per unit and never hard-code a static key across units. Verify with terragrunt plan that each unit targets its own state path, especially when refactoring folders.