HomeBlogTerraform Import Guide: How to Bring Existing Infrastructure into Terraform
InfrastructureProfessional TipsTechnologiesTerraform

Terraform Import Guide: How to Bring Existing Infrastructure into Terraform

image
10 mins
03.06.2025
Volodymyr Shynkar CEO and Co-Founder of AppRecode

Volodymyr Shynkar

CEO/CTO

Introduction

image

I’ve been there. You start small – maybe spin up an EC2 instance here, create an S3 bucket there. The AWS console feels friendly enough. A few CLI commands later, and boom – you’ve got something working.

But then months pass. Your startup grows. Suddenly you’re staring at dozens of resources scattered across multiple regions, created by different team members who all had their own “quick and dirty” approaches. Sound familiar?

This is exactly where terraform import becomes your lifesaver. I’m not talking about some magical tool that fixes everything overnight. Instead, it’s your bridge between the chaos you’ve inherited and the organized Infrastructure as Code world you desperately want to reach.

The best part? You don’t have to nuke everything and start fresh. I learned this the hard way after spending an entire weekend trying to recreate a production database cluster because I thought that was the “proper” way to do it.

Let me walk you through everything I wish someone had told me about terraform import when I was pulling my hair out trying to tame our infrastructure mess.

How terraform import Works

Think of terraform import as introducing two people who should’ve met ages ago. You’ve got your cloud resources just doing their thing, completely oblivious to Terraform. Meanwhile, Terraform’s sitting there with no clue these resources even exist.

The import command basically plays matchmaker. It tells Terraform “Hey, see that EC2 instance over there? Yeah, that’s yours now. Here’s everything you need to know about it.”

What happens behind the scenes is pretty straightforward. Terraform hits up your cloud provider’s API, grabs all the juicy details about that resource, and stuffs them into its state file. Nothing gets created or destroyed – it’s purely administrative.

But here’s where people trip up (myself included, embarrassingly enough): you need both pieces ready before you start. The actual resource needs to exist in your cloud, and you need a matching resource block in your Terraform code. Miss either one, and you’ll be scratching your head wondering why nothing works.

What You Can Import (and What You Can't)

Most of the stuff you actually care about day-to-day can be imported. I’m talking about your bread-and-butter resources:

Your compute stuff – EC2 instances, containers, whatever you’re running your apps on. Storage is usually fine too – S3 buckets, EBS volumes, that sort of thing. Network components? Yep, VPCs, subnets, security groups all play nice with imports.

Databases are where it gets interesting. RDS instances import just fine, but you’ll need to think about their parameter groups and subnet groups too. Don’t ask me how I know this.

IAM stuff generally works well – roles, policies, users. DNS records and SSL certificates? No problem.

But there are some things that just won’t cooperate:

Temporary credentials are a no-go (they expire anyway, so what’s the point?). Some provider-specific internal components are off-limits. And if you’ve got resources managed by other systems that conflict with Terraform, you’re going to have a bad time.

Step-by-Step: How to Import a Resource into Terraform

Let me show you how this works with a real terraform import example. I’ll use an S3 bucket because, let’s be honest, everyone’s got at least three of them lying around.

Step 1: Find Your Target Resource

First things first – figure out what you want to import. For this example, let’s say you’ve got an S3 bucket called my-existing-bucket. Creative name, I know.

Step 2: Write the Configuration

Before you can import anything, you need to write the Terraform configuration. This tripped me up initially – I kept trying to import first, then write the code. Wrong order.


resource "aws_s3_bucket" "existing_bucket" {
  bucket = "my-existing-bucket"
}

resource "aws_s3_bucket_versioning" "existing_bucket_versioning" {
  bucket = aws_s3_bucket.existing_bucket.id
  versioning_configuration {
   status = "Enabled"
  }
}

Step 3: Run the Import

Now for the fun part – the actual terraform import resource command:

terraform import aws_s3_bucket.existing_bucket my-existing-bucket

terraform import aws_s3_bucket_versioning.existing_bucket_versioning my-existing-bucket

Step 4: Check Your Work

After importing, you absolutely must run this:

terraform plan

If everything went right, you should see zero changes. Any differences mean your configuration doesn’t match reality, and you’ll need to adjust it. Don’t skip this step – I learned that lesson the expensive way.

If you’re using Terraform 1.5 or later, there’s a cleaner approach with terraform import block syntax:

import {
  to = aws_s3_bucket.existing_bucket
  id = "my-existing-bucket"
}

import {
  to = aws_s3_bucket_versioning.existing_bucket_versioning
  id = "my-existing-bucket"
}

resource "aws_s3_bucket" "existing_bucket" {
  bucket = "my-existing-bucket"
}

resource "aws_s3_bucket_versioning" "existing_bucket_versioning" {
  bucket = aws_s3_bucket.existing_bucket.id
  versioning_configuration {
    status = "Enabled"
  }
}

Then just run terraform plan and it handles the imports automatically. Much cleaner than the old way.

Real Case Study

I want to tell you about DataStream Analytics because their story hits close to home. Three years of rapid growth, and their AWS environment was what you’d politely call “organically grown.” Over 150 resources spread across multiple regions, each created by whoever happened to be on call that day.

Marcus Rodriguez, their Senior Infrastructure Engineer, described it perfectly: “We had reached a breaking point. Our deployment process was taking weeks instead of hours, and we were constantly battling configuration drift between environments. We needed Infrastructure as Code, but couldn’t afford the downtime of recreating everything.”

Marcus Rodriguez, Senior Infrastructure Engineer at DataStream Analytics 

Instead of panicking (like I would have), they got methodical about it:

Phase 1: Discovery and Documentation
They used AWS Config plus some custom scripts to catalog everything. Created a massive inventory with dependencies mapped out. Boring work, but essential.

Phase 2: Critical Path Import
Started with their production database cluster – the stuff that absolutely could not go down. Smart move. Import the scary stuff first while you’re fresh and caffeinated.

Phase 3: Incremental Adoption
Over four months, they gradually worked through everything else. Tested each batch in staging before touching production. No heroes, no shortcuts.

Phase 4: Validation and Optimization
Final phase was all about making sure everything behaved correctly under Terraform management. Lots of testing, lots of validation.

The transformation was incredible. “Using terraform cloud import functionality, we brought our entire infrastructure under code management without a single service interruption,” Marcus told me. “The key was patience and methodical testing at each step.”

Now they’re running a fully automated infrastructure pipeline using comprehensive devops services and solutions. Their deployment time went from weeks to minutes. That’s the power of doing imports right.

Common Mistakes and Pro Tips

Mistake 1: Ignoring Resource Dependencies

I see this constantly. People import an RDS instance and forget about its subnet group, security groups, parameter groups – all the stuff it depends on. It’s like trying to move just the wheels of a car and wondering why it doesn’t work.

Pro Tip: Map out your dependencies before you start. Import foundational pieces first, then build up. Trust me on this one.

Mistake 2: Configuration Drift After Import

This one burned me early on. You import a resource, get excited that it worked, then immediately start tweaking the Terraform configuration without making sure it matches what’s actually deployed. Recipe for disaster.

Pro Tip: Get a clean terraform plan output first (showing no changes), then make your modifications. Don’t be tempted to skip this step.

Mistake 3: Attempting Mass Imports

Trying to import 50 resources at once is like trying to learn piano by playing Rachmaninoff. You’ll just frustrate yourself and probably break something.

Pro Tip: Do 5-10 resources at a time. Validate each batch before moving on. This is especially crucial during cloud migration projects where you can’t afford mistakes.

Mistake 4: Insufficient State Management

Your Terraform state file is precious. I once corrupted a state file during imports and spent three days reconstructing it. Don’t be me.

Pro Tip: Always backup your state file before imports. Use remote state backends with versioning for anything important. Your future self will thank you.

Advanced Techniques

Once you’re comfortable with basic imports, you can start getting fancy with terraform import module patterns:

 

module "legacy_database" {

  source = "./modules/database"

  # Import existing RDS resources into this module

}

When you’re working with terraform import examples in a team environment, establish clear protocols. Document each import – why you did it, what depends on what, how you validated it worked. Future you (and your teammates) will appreciate the breadcrumbs.
For complex scenarios involving terraform import state management, you might need commands like terraform state mv to reorganize resources after import. It’s powerful stuff, but use it carefully.

Final Thoughts

Learning how to use terraform import was honestly one of the best investments I made in my Infrastructure as Code journey. Yeah, it takes planning and patience, but the payoff is enormous.

The secret sauce is understanding what you’re working with, planning your approach systematically, and taking it one step at a time. Don’t try to be a hero and import everything at once. I’ve seen too many people (myself included) make that mistake.

The terraform import statement functionality keeps getting better with each release. As cloud infrastructure gets more complex, being able to seamlessly integrate existing resources with Infrastructure as Code becomes more valuable than ever.

Frequently Asked Questions

Can I import EC2 without its VPC?

Absolutely. You can import an EC2 instance without importing its VPC. Your Terraform configuration just needs to reference the existing VPC correctly. The VPC doesn’t need to be managed by Terraform for the EC2 import to work.

Do I need to write the code before running import?

It’s highly recommended but not strictly required. Having the configuration ready makes the whole process smoother and lets you validate immediately with terraform plan. I always write the config first now.

What if the resource is already in another Terraform state?

You can’t import a resource that’s already managed by another Terraform state file. You’ll need to remove it from the original state using terraform state rm first. Be careful with this one.

Can I batch import all resources?

Terraform doesn’t have native batch import functionality, but you can script it for multiple resources. Tools like Terraformer can help automate discovery and import of existing resources, though you’ll still need to validate everything manually.

How does terraform import differ from tools like Terraformer?

Terraform import is the official way to bring individual resources into Terraform management. Terraformer is a third-party tool that automatically discovers existing resources and generates Terraform configurations for them. Terraformer is great for large-scale imports but you’ll need to thoroughly validate the generated configurations.

Did you like the article?

1 ratings, average 4.9 out of 5

Comments

Loading...

Blog

OUR SERVICES

REQUEST A SERVICE

651 N Broad St, STE 205, Middletown, Delaware, 19709
Ukraine, Lviv, Studynskoho 14

Get in touch

Contact us today to find out how DevOps consulting and development services can improve your business tomorrow.