Refactoring, importing and OpenTofu
🎯You'll be able to
Rename or move resources without recreating them, bring existing infrastructure under Terraform, and explain how OpenTofu relates to Terraform.
🏠The everyday picture
When a city renames a road, the houses don't move; only the address changes, and the post office updates its records. And when a new municipality takes over an old village, it adds the existing houses to its register instead of rebuilding them.
📘What it really is
-
Renaming: changing
docker_container.lbtodocker_container.load_balancermakes Terraform think one was removed and another added. Amovedblock tells it they're the same:hcl moved { from = docker_container.lb to = docker_container.load_balancer }Keepmovedblocks for a while, so every environment and every colleague's branch picks up the move. -
Importing: for something created by hand that Terraform should now manage, write the resource and an
importblock (Terraform 1.5 and later):hcl import { to = docker_volume.uploads id = "routerani-dev-uploads" }terraform planshows it aswill be imported;terraform plan -generate-config-out=generated.tfcan even draft the resource for you to tidy. The older commandterraform import ADDRESS IDdoes the same without a reviewable file. -
Stopping management without deleting: a
removedblock (Terraform 1.7 and later) withlifecycle { destroy = false }forgets a resource from state and leaves it running.terraform state rmdoes the same from the command line. -
OpenTofu: in August 2023 HashiCorp changed Terraform's licence from the open-source MPL to the Business Source License, which limits some commercial uses. A group of companies forked the last open version as OpenTofu, now hosted by the Linux Foundation.
- It uses the same language and the same providers, with the
tofucommand (tofu init,tofu plan). - Most configurations work in both. Newer features differ: OpenTofu added client-side state encryption; Terraform added features of its own. Check compatibility before switching an existing setup.
- For learners, the concepts are the same. Choose based on your team's licence needs and tooling.
📝A worked example
Input: in your finished kit, rename docker_container.lb to docker_container.load_balancer (and anything that refers to it), add the
moved block above, and run terraform plan.
Expected output: docker_container.lb has moved to docker_container.load_balancer and Plan: 0 to add, 0 to change, 0 to destroy. Remove the
moved block and plan again: Terraform now proposes to destroy docker_container.lb and create docker_container.load_balancer, which would
interrupt traffic. Put the block back.
🌍Where it's used
- Clean-ups of old configurations, renaming resources to a new standard without downtime.
- Adopting IaC: teams import the hand-made production servers, network by network, before changing anything.
- Licence decisions: some companies and vendors standardise on OpenTofu, others on Terraform with HCP Terraform.
📝Case scenario
A media company decided to manage its hand-built DNS records with Terraform. A first attempt wrote new records with the same names and applied
them, which failed with conflicts and briefly broke email. The second attempt used import blocks: the plan showed 120 records will be
imported and zero changes, which was approved, and from then on DNS changes went through pull requests.
🖱️Try it
Create a volume by hand: docker volume create routerani-dev-uploads. Add a docker_volume.uploads resource with that name and the import
block above, and run terraform plan, then terraform apply. Success: the plan shows 1 to import, 0 to add, and afterwards
terraform state list includes docker_volume.uploads. Remove the resource with a removed block if you don't want to keep it.
⚠️Common mistakes
- Renaming without
moved. Sign: a plan that destroys and recreates something you only renamed. Fix: amovedblock. - Recreating instead of importing. Sign: conflicts or duplicates when Terraform meets what already exists. Fix:
importblocks, then a plan with no changes. - Switching tools mid-change. Sign: state written by one tool version that the other can't read. Fix: switch in a planned step, after checking compatibility.
🛠️For your project
If you rename anything in RouteRani's Terraform during the projects, add moved blocks so the plan shows no replacements.
✅Quick check
What does a moved block do?
Show the answer
Tells Terraform a resource has a new address, so it updates state instead of destroying and recreating it.
What is OpenTofu?
Show the answer
An open-source fork of Terraform, with the same language and providers and the tofu command.
