IaCInfrastructure as Codeterraformterraform datasources

Terraform Data Sources — Reading Existing Infrastructure Instead of Creating It

Learn what Terraform Data Sources are, when to use them, how Terraform reads existing infrastructure, and how to combine Data Sources with Resources in real-world projects.

Jul 22, 20265 min readUpdated Jul 22, 2026
Terraform Data Sources — Reading Existing Infrastructure Instead of Creating It

Terraform Data Sources — Reading Existing Infrastructure Instead of Creating It

In the previous article, we learned about Terraform Modules and how they help us organize infrastructure into reusable building blocks.

However, in the real world, not every piece of infrastructure is created by Terraform.

Many resources already exist.

For example:

  • A VPC managed by the platform team.
  • A database provisioned by the DBA team.
  • An EKS cluster created using an infrastructure blueprint.
  • A DNS hosted zone that has existed for years.
  • An AWS account containing hundreds of existing resources.

If Terraform could only create new infrastructure, it would be difficult to adopt in large organizations.

This is exactly why Data Sources exist.


Terraform Doesn't Only Create Resources

When people first learn Terraform, they often imagine a workflow like this:

Terraform
      ↓
Create Resource

In reality, Terraform has another extremely important capability:

Terraform
      ↓
Read Existing Infrastructure
      ↓
Use Information
      ↓
Create New Infrastructure

In other words:

Terraform doesn't just create infrastructure.

It can also read infrastructure that already exists.

That's the purpose of Data Sources.


Resource vs Data Source

Terraform has two concepts that are often confused.

Resource

A Resource is responsible for managing the lifecycle of infrastructure.

For example:

code
resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
}

Terraform will:

  • create
  • update
  • destroy

this resource whenever necessary.

Terraform owns its entire lifecycle.


Data Source

A Data Source has only one responsibility:

Read information.

For example:

code
data "aws_vpc" "main" {
  default = true
}

Terraform will:

  • call the AWS API
  • find the default VPC
  • retrieve its information
  • store the result in memory

Terraform does not create the VPC.

Terraform does not modify the VPC.

Terraform does not delete the VPC.

It simply reads it.


An Easy Way to Think About It

Imagine Terraform as an office employee.

There are two different actions.

Resource

"Create a new employee."

Terraform will:

  • create the record
  • manage it
  • update it
  • remove it

Data Source

"Find an employee named John."

Terraform opens the company database.

Reads the information.

Uses it later.

Nothing is modified.


Data Source Syntax

The syntax looks almost identical to a Resource.

code
data "<provider>_<type>" "<name>" {
 
}

For example:

code
data "aws_availability_zones" "available" {}

Or:

code
data "aws_caller_identity" "current" {}

Or:

code
data "aws_region" "current" {}

Or:

code
data "aws_vpc" "main" {
  default = true
}

After Terraform reads the resource, its attributes become available just like Resource attributes.

For example:

code
data.aws_vpc.main.id

Or:

code
data.aws_region.current.name

When Are Data Sources Read?

Terraform's workflow now becomes:

Configuration
      ↓
Read Data Sources
      ↓
Refresh Resources
      ↓
Build Execution Plan
      ↓
Apply

One important difference is that Terraform always reads Data Sources before generating the execution plan.

This ensures that the plan uses the latest information from the cloud provider.


A Real-World Example

Suppose your company already has a production VPC.

You only need to deploy an EC2 instance.

You shouldn't recreate the VPC.

Instead:

code
data "aws_vpc" "main" {
  tags = {
    Name = "production-vpc"
  }
}

Then:

code
resource "aws_security_group" "web" {
  vpc_id = data.aws_vpc.main.id
}

And later:

code
resource "aws_instance" "web" {
  subnet_id = data.aws_subnets.private.ids[0]
}

Terraform will do this:

Read Existing VPC
        ↓
Read Existing Subnets
        ↓
Create Security Group
        ↓
Create EC2

Nothing is recreated.


Another Example

Which AWS account is Terraform currently using?

You can retrieve it with:

code
data "aws_caller_identity" "current" {}

Then:

code
output "account_id" {
  value = data.aws_caller_identity.current.account_id
}

Or:

code
output "user_id" {
  value = data.aws_caller_identity.current.user_id
}

This is one of the most commonly used Data Sources in reusable Terraform modules.


Reading the Current Region

Terraform can also detect the active AWS region.

code
data "aws_region" "current" {}

Then:

code
output "region" {
  value = data.aws_region.current.name
}

Instead of hardcoding:

ap-southeast-1

your modules become much more portable.


Reading Availability Zones

Another very common example.

code
data "aws_availability_zones" "available" {}

Then:

code
resource "aws_subnet" "private" {
  availability_zone = data.aws_availability_zones.available.names[0]
}

Terraform always retrieves the available AZs automatically.

Instead of hardcoding:

ap-southeast-1a

your module works across different AWS regions.


Combining Resources and Data Sources

This is the most common architecture.

                Existing Infrastructure

                  VPC
                  Subnet
                  Route Table
                  Hosted Zone

                        │
                        ▼

                 Terraform Data Sources

                        │
                        ▼

                Terraform Resources

                  EC2
                  ECS
                  RDS
                  Lambda

Existing infrastructure is accessed through Data Sources.

New infrastructure is created with Resources.

Together, they form a complete infrastructure deployment.


Are Data Sources Stored in Terraform State?

This is a common question.

The answer is:

Yes.

But unlike Resources, Terraform does not manage their lifecycle.

Terraform stores the retrieved information in the state for the current operation.

Whenever you run terraform plan again, Terraform reads the Data Sources again to ensure the information is up to date.


Common Mistakes

1. Expecting a Data Source to Create Resources

For example:

code
data "aws_vpc" "main" {
    cidr_block = "10.0.0.0/16"
}

Some beginners assume Terraform will create a VPC.

It won't.

Terraform will search for a VPC matching that CIDR block.

If none exists:

No matching VPC found

2. Hardcoding Resource IDs

For example:

code
vpc_id = "vpc-123456"

This makes your module difficult to reuse.

A better approach is:

code
vpc_id = data.aws_vpc.main.id

3. Reading Too Many Data Sources

Every Data Source requires one or more API calls.

A large project might look like this:

Terraform Plan
      ↓
500 API Calls

Planning becomes noticeably slower.

Only query the information you actually need.


Best Practices

  • Use Data Sources only for existing infrastructure.
  • Avoid hardcoding resource IDs whenever they can be discovered automatically.
  • Combine Resources and Data Sources instead of trying to manage everything within a single Terraform project.
  • Give Data Sources meaningful names such as current, main, default, or production.
  • Avoid unnecessary Data Sources because each one requires API requests to the cloud provider.

Summary

Data Sources are one of Terraform's most important features.

If Resources allow Terraform to create and manage infrastructure, Data Sources allow Terraform to understand infrastructure that already exists.

In real-world projects, almost every Terraform configuration uses both Resources and Data Sources together.

You'll rarely encounter an environment where Terraform creates everything from scratch.

Instead, Terraform usually starts by reading existing infrastructure before provisioning anything new.

That's why Data Sources are an essential part of working with Terraform.


Next Up

So far we've covered:

  • Terraform Configuration
  • Terraform State
  • Terraform Modules
  • Terraform Data Sources

However, there's still one fundamental concept that many beginners misunderstand:

How do Terraform Variables actually work?

Many developers think Variables are simply a place to store values like:

  • Region
  • Instance Type
  • Environment

In reality, Variables are the foundation for building reusable, configurable Terraform modules that can be deployed across multiple environments.

In the next article, we'll dive deep into Terraform Variables, including how they work, variable scopes, precedence rules, and best practices used in production environments.

Comments

0/2000

Loading comments…