DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Implement Amazon S3 Cross-Region Replication With Terraform
  • Streamlining HashiCorp Cloud Platform (HCP) Deployments With Terraform
  • Automating AWS Infrastructure Testing With Terratest
  • Setting Up a ScyllaDB Cluster on AWS Using Terraform

Trending

  • While Performing Dependency Selection, I Avoid the Loss Of Sleep From Node.js Libraries' Dangers
  • A Guide to Developing Large Language Models Part 1: Pretraining
  • Rethinking Recruitment: A Journey Through Hiring Practices
  • Unlocking AI Coding Assistants Part 1: Real-World Use Cases
  1. DZone
  2. Coding
  3. Tools
  4. Using Terraform Moved Block to Refactor Resources

Using Terraform Moved Block to Refactor Resources

Terraform moved block, introduced in version 1.1.0, provides a straightforward way to refactor resources by explicitly mapping old resource addresses to new ones.

By 
Mariusz Michalowski user avatar
Mariusz Michalowski
·
Mar. 28, 25 · Tutorial
Likes (1)
Comment
Save
Tweet
Share
3.3K Views

Join the DZone community and get the full member experience.

Join For Free

Terraform introduced the moved block in version 1.1.0. This block provides a straightforward way to refactor resources by explicitly mapping old resource addresses to new ones. It significantly reduces the risk of losing state or manually managing imports during renames or moves.

In this article, we’ll explain what the moved block is and how to use it to streamline resource restructuring for smoother and safer Terraform updates.

What Is the Terraform Moved Block?

A Terraform moved block is used within a module’s moved section to declare the migration of a resource or data source from one address to another. It is helpful for refactoring Terraform code while ensuring that state information is preserved, preventing Terraform from destroying and recreating resources unnecessarily.

The moved block also handles resource renaming or movement across modules, making state management seamless.

The syntax of the Terraform moved block is as follows:

Plain Text
 
moved {
  from = "<old_address>"
  to   = "<new_address>"
}


Where:

  • from is the original address of the resource or module in the previous configuration
  • to is the new address of the resource or module in the updated configuration

When to Use the Terraform Moved Block?

The moved block in Terraform is used when you need to refactor or rename resources in your configuration without destroying and recreating them. It can be useful for:

  • Renaming resources: When you change the name of a resource within the configuration (e.g., aws_instance.old_name to aws_instance.new_name).
  • Reorganizing modules: If a resource is moved between modules or changed from a root-level resource to a module-managed resource (or vice versa), you can use the moved block to keep Terraform aware of the transition.
  • Refactoring module names: When you are renaming or reorganizing modules to align with new naming conventions or standards.
  • Changing resource block types: If you change the type of a resource block (e.g., from google_compute_instance to google_compute_engine), the moved block maps the old resource to the new type. Note that this is possible only if the configurations are compatible and the resource’s state remains valid. 
  • Splitting or consolidating configurations: When you split a configuration into multiple files or modules or consolidate it into fewer files, use the moved block to reflect these changes without resource re-creation.

How to Use the Terraform Moved Block

Let’s consider some examples:

Example 1: Renaming a Resource

In this example, we will rename a Terraform resource from aws_instance.old_name to aws_instance.new_name.

Plain Text
 
# Old Configuration
# This block is no longer present
resource "aws_instance" "old_name" {
  ami           = "ami-12345678"
  instance_type = "t2.micro"
}

# New Configuration
resource "aws_instance" "new_name" {
  ami           = "ami-12345678"
  instance_type = "t2.micro"
}

# Moved Block
moved {
  from = "aws_instance.old_name"
  to   = "aws_instance.new_name"
}


Here, the moved block tells Terraform that the resource aws_instance.old_name has been renamed to aws_instance.new_name. 

Note: After making these changes, make sure you run terraform plan to verify that Terraform recognizes the migration correctly and that no unnecessary changes will be applied. 

Example 2: Moving Resources Between Modules

In the next example, a resource is moved from the root module to a nested module.

We want the aws_s3_bucket.my_bucket resource to be moved from the root module to a module named storage:

Plain Text
 
# Old Configuration (Root Module)
# This block is no longer present
resource "aws_s3_bucket" "my_bucket" {
  bucket = "example-bucket"
}

# New Configuration (Nested Module)
# modules/storage/main.tf
resource "aws_s3_bucket" "my_bucket" {
  bucket = "example-bucket"
}

# Root Module Configuration
module "storage" {
  source = "./modules/storage"
}

# Moved Block
moved {
  from = "aws_s3_bucket.my_bucket"
  to   = "module.storage.aws_s3_bucket.my_bucket"
}


The moved block updates the Terraform state to reflect the new location without destroying and recreating the resource.

Example 3: Using Moved With for_each

We will now move a resource to a new name using a for_each loop, which creates multiple resources dynamically. 

Plain Text
 
# Old Configuration
# This block is no longer present
resource "aws_security_group" "old_group" {
  for_each = toset(["web", "db"])
  name     = "sg-${each.key}"
}

# New Configuration
resource "aws_security_group" "new_group" {
  for_each = toset(["web", "db"])
  name     = "sg-${each.key}"
}

# Moved Block
moved {
  from = "aws_security_group.old_group[\"web\"]"
  to   = "aws_security_group.new_group[\"web\"]"
}

moved {
  from = "aws_security_group.old_group[\"db\"]"
  to   = "aws_security_group.new_group[\"db\"]"
}


Each resource in the old_group is mapped to a corresponding resource in new_group using moved blocks. This ensures a smooth state migration for all instances of the resources without unnecessary recreation.

Example 4: Moving a Resource With a Changed Identifier

In this example, a resource’s identifier changes because the for_each key expression is modified. 

We want to rename the for_each keys from ["app", "db"] to ["frontend", "database"]. Without the moved block, Terraform would see these as new resources and destroy the old ones.

Plain Text
 
# Old Configuration
resource "aws_security_group" "sg" {
  for_each = toset(["app", "db"])
  name     = "sg-${each.key}"
}

# New Configuration
resource "aws_security_group" "sg" {
  for_each = toset(["frontend", "database"])  # Changed identifiers
  name     = "sg-${each.key}"
}

# Moved Blocks
moved {
  from = "aws_security_group.sg[\"app\"]"
  to   = "aws_security_group.sg[\"frontend\"]"
}

moved {
  from = "aws_security_group.sg[\"db\"]"
  to   = "aws_security_group.sg[\"database\"]"
}


Each moved block maps the old key (app or db) to the new key (frontend or database).

When you run terraform plan and terraform apply, Terraform updates the state to match the new identifiers, avoiding unnecessary destruction and re-creation of the security groups.

Example 5: Moving a Resource Between Providers

If we want to migrate a resource from one provider to another (e.g., from aws to aws.other_region), the Terraform moved block ensures a seamless state transition.

In our example, the S3 bucket resource is initially in the us-west-1 region using the default aws provider. We want to manage the same bucket in a different AWS region (e.g., us-east-1) using a different provider alias.

Plain Text
 
# Old Configuration
provider "aws" {
  region = "us-west-1"
}

resource "aws_s3_bucket" "example_bucket" {
  bucket = "example-bucket"
}

# New Configuration
provider "aws" {
  region = "us-west-1"
}

provider "aws" {
  alias  = "other_region"
  region = "us-east-1"
}

resource "aws_s3_bucket" "example_bucket" {
  provider = aws.other_region
  bucket   = "example-bucket"
}

# Moved Block
moved {
  from = "aws_s3_bucket.example_bucket"
  to   = "aws_s3_bucket.example_bucket"
}


The moved block ensures Terraform updates the state to associate the resource with the new provider configuration (aws.other_region). The bucket itself remains intact in AWS and is not recreated, avoiding downtime or data loss.

Terraform Moved Block Limitations

The moved block in Terraform is useful for handling resource renaming or moving across modules in a safe and structured manner, but it has some limitations:

  • Manual specification. The moved block requires you to manually specify both the source and destination addresses, which can lead to human error if the information is not provided accurately.
  • Resource renames only. The moved block is specifically designed for renaming or moving resources within the state. Splitting or restructuring state might require manual state modifications or the use of tools like terraform state mv.
  • Static declaration. The moved block is static and does not support conditional logic. It cannot handle scenarios in which the movement depends on dynamic conditions.
  • Limited to planned changes. The moved block is only applied during the terraform plan and apply commands. If you modify the state file manually, the moved block will not help reconcile those changes.
  • Requires state compatibility. The source and destination must be part of the same state file. This is particularly important for users working with remote backends.
  • Only supported in Terraform 1.1+. Older versions of Terraform do not recognize the moved block, making it incompatible with legacy configurations or environments.

Key Points

The moved block in Terraform is a practical tool for restructuring resources without disrupting infrastructure. It ensures seamless state updates, avoids downtime, and simplifies complex refactoring tasks, allowing you to reorganize code confidently and maintain operational stability — provided the mappings are accurate and proper planning is in place.

AWS Blocks Terraform (software)

Published at DZone with permission of Mariusz Michalowski. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Implement Amazon S3 Cross-Region Replication With Terraform
  • Streamlining HashiCorp Cloud Platform (HCP) Deployments With Terraform
  • Automating AWS Infrastructure Testing With Terratest
  • Setting Up a ScyllaDB Cluster on AWS Using Terraform

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

OSZAR »