You’ve probably hit this scenario at least once: a resource was created under the wrong Terraform project, or your architecture evolved and now that resource belongs somewhere else. The naive approach? Delete and recreate it. The real-world approach? Avoid downtime and preserve state.
Moving a Terraform resource between projects is less about the infrastructure itself and more about carefully handling Terraform state. Let’s walk through how this works in practice.
Why this is tricky
Terraform tracks resources using its state file. If you simply copy configuration from one project to another, Terraform in the new project has no idea that the resource already exists. It will try to create it again — which usually fails or causes conflicts.
Meanwhile, the old project still thinks it owns the resource. If you run terraform apply there, it may attempt to destroy it.
The goal is to move ownership in the state — not recreate the infrastructure.
Two main approaches
There are two safe ways to move a resource between Terraform projects:
- Using terraform state mv (best when both states are accessible)
- Using terraform import (more flexible, works across backends)
Approach 1: Using terraform state mv
This is the cleanest option when you can access both state files locally or via a shared backend.
Step 1: Pull both states locally
If you're using remote backends (like S3 or Terraform Cloud), pull them first:
1terraform state pull > source.tfstate
2terraform state pull > destination.tfstateStep 2: Move the resource
Use the state mv command with explicit state files:
1terraform state mv \
2 -state=source.tfstate \
3 -state-out=destination.tfstate \
4 aws_s3_bucket.old_project_bucket \
5 aws_s3_bucket.new_project_bucketThis removes the resource from the source state and inserts it into the destination state.
Step 3: Push updated states back
1terraform state push source.tfstate
2terraform state push destination.tfstateAt this point, Terraform ownership has been transferred.
Step 4: Update configuration
Make sure:
- The resource is removed from the old project
- The resource is defined in the new project
- The resource name matches the new state address
Approach 2: Using terraform import (most common in teams)
In many setups, especially with remote backends, directly manipulating state files isn’t practical. That’s where terraform import comes in.
Here’s the safer, more common workflow.
Step 1: Remove resource from old state (without deleting it)
1terraform state rm aws_s3_bucket.old_project_bucketThis tells Terraform: “Stop managing this resource,” but it does not delete the actual infrastructure.
Step 2: Add resource configuration to new project
Define the same resource in your new Terraform project:
1resource "aws_s3_bucket" "new_project_bucket" {
2 bucket = "my-existing-bucket"
3}Step 3: Import the existing resource
1terraform import aws_s3_bucket.new_project_bucket my-existing-bucketNow the new project owns the resource.
Step 4: Run plan to verify
1terraform planIf everything is aligned, Terraform should show no changes.
Common mistakes developers make
Here’s where things usually go wrong:
- Forgetting to remove from old state → leads to accidental deletion
- Mismatched configuration → Terraform tries to modify the resource after import
- Wrong resource address → import succeeds but attaches incorrectly
- Skipping plan step → surprises during apply
A good rule: after import, your plan should be boring.
What about modules?
If the resource lives inside a module, the address becomes more specific:
1module.storage.aws_s3_bucket.bucketSo your import would look like:
1terraform import module.storage.aws_s3_bucket.bucket my-existing-bucketSame concept — just a longer address.
Handling different providers or accounts
If you're moving a resource across projects that use different credentials or accounts, things get more nuanced.
Terraform can only import a resource if the provider configuration can access it. That means:
- Credentials must point to the correct account
- Region must match
- Permissions must allow read access
If those don’t align, import will fail even if the resource exists.
Zero-downtime checklist
If avoiding downtime is critical, run through this before making changes:
- Do not run apply in the old project after removing state
- Verify resource identifiers (IDs, ARNs, names)
- Ensure configuration parity before import
- Always run terraform plan after import
A quick mental model
Think of Terraform like a registry of ownership:
- State file = who owns what
- Configuration = how it should look
Moving a resource isn’t about rebuilding — it’s about transferring ownership cleanly.
When to prefer each method
- Use state mv when you control both states and want a precise transfer
- Use import when working across teams, backends, or environments
In most real-world DevOps setups, import is the safer and more portable option.
Final thought
Terraform gives you powerful tools to reshape infrastructure without tearing it down — but it expects you to be explicit. Moving a resource between projects is one of those operations where being careful pays off immediately.
If you treat the state as a first-class concern, these migrations become routine instead of risky.