# terraform / data-sources / lookups
Fetch What Already Exists: Data Sources
Not every piece of infrastructure is created by your current Terraform code. Data sources allow Terraform to query existing cloud resources — like the latest Ubuntu AMI, corporate VPCs, active subnets, or your AWS Account ID — and use their attributes without taking over their lifecycle.
Read-Only Infrastructure
In real production teams, infrastructure is layered. The network engineering team might build the VPC and subnets, the security team provides standard base AMIs, and your team provisions application servers inside that network. Data sources let you wire these pieces together effortlessly.
| Aspect | resource block | data block |
|---|---|---|
| Operation | Create, Update, Destroy | Read & Query only |
| Lifecycle Control | Terraform owns the resource | Terraform never touches or deletes it |
| State File | Tracks configuration & IDs | Caches queried attributes |
| Destruction | terraform destroy terminates it | Ignored during destroy |
Why Hardcoding IDs Fails
An AMI ID like ami-0c55b159cbfafe1f0 only exists in us-east-1. If your deployment switches to ap-south-1 (Mumbai) or eu-west-1 (Ireland), your Terraform build will crash. Data sources query the provider API dynamically in whatever region is currently active.
Data Block Structure
data "TYPE" "LOCAL_NAME" { # Filter arguments to find the target argument_1 = "value" } # Reference anywhere in the configuration: resource "aws_instance" "app" { ami = data.TYPE.LOCAL_NAME.id }
data.TYPE.LOCAL_NAME.ATTRIBUTE
Every data source is accessed via the data. prefix. This makes it instantly obvious when reading code that an attribute came from an external query rather than a managed resource.
Production Pattern: Dynamic Ubuntu AMI Lookup
data "aws_ami" "ubuntu_latest" { most_recent = true owners = ["099720109477"] # Canonical's Official AWS Account ID filter { name = "name" values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"] } filter { name = "virtualization-type" values = ["hvm"] } } resource "aws_instance" "web" { ami = data.aws_ami.ubuntu_latest.id instance_type = "t3.micro" }
Always Specify the "owners" Argument
Anyone can publish a public AMI to the AWS Marketplace with the name ubuntu-22.04. Specifying Canonical's verified AWS Account ID (099720109477) or Amazon Linux (amazon) ensures you never boot malicious third-party images.
Auto Patching on Fresh Deployments
Because most_recent = true is set, new environments automatically inherit the latest security-patched kernel release from Canonical.
Querying Pre-Existing VPCs & Subnets
# 1. Fetch the default VPC or query by tag data "aws_vpc" "selected" { default = true } # 2. Fetch all public subnet IDs inside that VPC data "aws_subnets" "public" { filter { name = "vpc-id" values = [data.aws_vpc.selected.id] } } # 3. Use the first subnet to launch an instance resource "aws_instance" "web" { ami = data.aws_ami.ubuntu_latest.id subnet_id = data.aws_subnets.public.ids[0] }
Zero Hardcoded Network IDs
Notice that this entire configuration runs without a single hardcoded vpc-xxxxxxxx or subnet-xxxxxxxx string. You can execute this template in any AWS account and region, and it adapts dynamically.
Querying AWS Account ID & Current Region
data "aws_caller_identity" "current" {} data "aws_region" "current" {} # Outputs contextual information output "account_id" { value = data.aws_caller_identity.current.account_id } output "region_name" { value = data.aws_region.current.name }
Constructing Exact IAM ARNs
When generating IAM policies or S3 bucket policies that require an ARN like arn:aws:iam::123456789012:root, you can use data.aws_caller_identity.current.account_id rather than hardcoding the 12-digit account number.
Data Sources Quick Summary
| Rule | Explanation |
|---|---|
| Exact Matching | If a data query returns 0 results or >1 result where 1 was expected (like aws_ami), Terraform will error during plan. |
| Read-Only Safety | Running terraform destroy will never delete resources queried through a data block. |
| Use Filters Judiciously | Combine multiple filters (e.g. tag + VPC ID) to ensure queries resolve to exact unambiguous targets. |