DEV Community

Renaming Terragrunt Projects Without Migrating State

The Problem

By default, Terragrunt derives your remote state key from the file path of the module. Something like:

# root.hcl
remote_state {
  backend = "s3"
  generate = {
    path = "backend.tf"
    if_exists = "overwrite"
  }
  config = {
    bucket = "your-terraform-state-bucket"
    key = "${path_relative_to_include()}/terraform.tfstate"
    region = "eu-west-1"
  }
}

path_relative_to_include() is convenient until the day you move projects/old-name/ to projects/new-name/. The key changes, Terraform can no longer find the state for those resources, and you're one terragrunt apply away from either a pile of "already exists" errors or, worse, Terraform trying to recreate live infrastructure because it thinks it's gone.

The usual fixes are painful: terraform state mv per resource, or a full terraform import pass. Both work, both are slow, both are one typo away from downtime on something that's just supposed to be a folder rename.

The Pattern: Decouple the State Key from the File Path

Give every project a project.hcl with a legacy_prefix - the state key it should keep, independent of wherever the folder happens to live today:

# projects/new-name/project.hcl
locals {
  legacy_prefix = "old-name" # the prefix this project's state has always used
  aws_region    = "eu-west-1"
}

Then have root.hcl build the state key from that prefix instead of the live path:

# root.hcl
locals {
  project = read_terragrunt_config(find_in_parent_folders("project.hcl"))
}

remote_state {
  backend = "s3"
  generate = {
    path = "backend.tf"
    if_exists = "overwrite"
  }
  config = {
    bucket = "your-terraform-state-bucket"
    key = "${local.project.locals.legacy_prefix}/terraform.tfstate"
    region = "eu-west-1"
  }
}

Now the folder path is free to change. Rename it, move it, restructure the whole repo - the state key is pinned to legacy_prefix, not to path_relative_to_include().

A new project just sets legacy_prefix to whatever it wants (usually matching its own path, since it has no history to preserve); an existing project keeps its old prefix forever, regardless of where the folder lives.

The Proof, Not Just the Theory

Don't take "it should work" on faith. Before you consider a reorganization safe, run terragrunt plan on every module you touched, and the only acceptable output is:

Plan: 0 to add, 0 to change, 0 to destroy.

Anything else means the key computation didn't land on the same value as before, and you stop right there. This one-line proof requirement is what makes the whole pattern trustworthy enough to use on live infrastructure: you're not hoping the refactor is safe, you're verifying it before it touches anything.

When This Is Worth It

This pattern earns its keep the moment you have more than a few Terragrunt modules and expect to reorganize them more than once - a new team convention, a naming scheme that didn't survive contact with reality, projects that outgrew their original folder structure. If you have three modules that will never move, plain path_relative_to_include() is simpler and you don't need this.

The core idea generalizes beyond Terragrunt: whenever a tool derives a stable identifier (a state key, a resource ID, a cache key) from something that isn't actually stable (a file path, a display name), that's worth decoupling explicitly - before the first painful migration forces you to do it under pressure.

Comments

No comments yet. Start the discussion.