Data Sources

4 minute read

Welcome to Module 7

In this module, you’ll learn how to implement data sources that allow Terraform users to query and reference existing infrastructure. Data sources are read-only and enable configurations to incorporate information from resources not managed by Terraform.

What You’ll Learn

By the end of this module, you’ll be able to:

  • ✅ Understand data source concepts and use cases
  • ✅ Implement data source schema design
  • ✅ Create Read operations for data sources
  • ✅ Implement filtering and search patterns
  • ✅ Handle single vs. multiple result scenarios
  • ✅ Build efficient data source queries
  • ✅ Apply data source best practices
  • ✅ Test data sources thoroughly

Module Contents

This module contains 8 comprehensive chapters:

Foundation

  1. Data Source Basics (20 min)
    • What are data sources
    • Resources vs. data sources
    • Data source interfaces
    • When to use data sources
    • Common patterns

Implementation

  1. Data Source Schema (25 min)
    • Schema design principles
    • Required vs. optional attributes
    • Computed attributes
    • Filter blocks
    • Validation
  2. Data Source Read (30 min)
    • Read operation implementation
    • Querying APIs
    • Error handling
    • Setting computed values
    • Not found scenarios
  3. Data Source Filtering (30 min)
    • Filter patterns
    • Multiple filter criteria
    • Tag filtering
    • Name patterns
    • Complex queries
  4. Handling Lists (25 min)
    • Multiple results
    • Single vs. list data sources
    • Most recent patterns
    • Sorting and limiting
    • Error handling

Practice

  1. Data Sources Lab (60 min)
    • Build complete data sources
    • Single result lookup
    • Filtered queries
    • List handling
    • Testing
  2. Data Sources Practice (45 min)
    • Comprehensive questions
    • Real-world scenarios
    • Best practices
    • Troubleshooting

Why Data Sources Matter

Data sources enable:

# Look up existing VPC
data "mycloud_vpc" "existing" {
  name = "production-vpc"
}

# Use data source output in resource
resource "mycloud_subnet" "app" {
  vpc_id = data.mycloud_vpc.existing.id
  cidr   = "10.0.1.0/24"
}

Key benefits:

  • Reference existing infrastructure
  • Fetch configuration values
  • Avoid hardcoding IDs
  • Enable modular configurations
  • Support multi-provider setups

Data Source vs. Resource

Aspect Data Source Resource
Purpose Query existing Manage lifecycle
Operations Read only CRUD
State Cached results Full state tracking
Changes Cannot modify Creates/updates/deletes
Usage data "type" "name" resource "type" "name"
Refresh Every plan Only on explicit read

Common Data Source Patterns

1. Lookup by Name

data "mycloud_database" "app_db" {
  name = "production-database"
}

output "db_endpoint" {
  value = data.mycloud_database.app_db.endpoint
}

2. Filter by Tags

data "mycloud_instances" "web_servers" {
  filter {
    name   = "tag:Role"
    values = ["web"]
  }
  
  filter {
    name   = "tag:Environment"
    values = ["production"]
  }
}

3. Get Most Recent

data "mycloud_ami" "latest" {
  most_recent = true
  
  filter {
    name   = "name"
    values = ["ubuntu-22.04-*"]
  }
}

4. List Multiple Results

data "mycloud_availability_zones" "available" {
  state = "available"
}

output "az_names" {
  value = data.mycloud_availability_zones.available.names
}

Implementation Overview

Basic data source structure:

type DatabaseDataSource struct {
    client *client.Client
}

type DatabaseDataSourceModel struct {
    ID       types.String `tfsdk:"id"`
    Name     types.String `tfsdk:"name"`
    Endpoint types.String `tfsdk:"endpoint"`
    Port     types.Int64  `tfsdk:"port"`
    Tags     types.Map    `tfsdk:"tags"`
}

func (d *DatabaseDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
    var config DatabaseDataSourceModel
    req.Config.Get(ctx, &config)
    
    // Query API
    db, err := d.client.GetDatabaseByName(ctx, config.Name.ValueString())
    if err != nil {
        resp.Diagnostics.AddError("Query Failed", err.Error())
        return
    }
    
    // Set all attributes
    config.ID = types.StringValue(db.ID)
    config.Endpoint = types.StringValue(db.Endpoint)
    config.Port = types.Int64Value(int64(db.Port))
    
    // Save to state
    resp.State.Set(ctx, config)
}

Real-World Use Cases

Infrastructure Discovery

# Find existing network configuration
data "mycloud_vpc" "main" {
  tags = {
    Name = "main-vpc"
  }
}

data "mycloud_subnets" "private" {
  vpc_id = data.mycloud_vpc.main.id
  
  filter {
    name   = "tag:Type"
    values = ["private"]
  }
}

Multi-Region Deployments

# Get available regions
data "mycloud_regions" "all" {
  filter {
    name   = "opt-in-status"
    values = ["opted-in"]
  }
}

# Deploy to each region
resource "mycloud_instance" "regional" {
  for_each = toset(data.mycloud_regions.all.names)
  
  region        = each.value
  instance_type = "t3.micro"
}

Service Discovery

# Find RDS endpoint
data "mycloud_database" "shared" {
  name = "shared-services-db"
}

# Configure application
resource "mycloud_app" "api" {
  database_url = data.mycloud_database.shared.endpoint
}

Learning Path

graph TD
    A[Data Source Basics] --> B[Schema Design]
    B --> C[Read Operation]
    C --> D[Filtering]
    D --> E[List Handling]
    E --> F[Lab Exercise]
    F --> G[Practice Questions]
    
    style A fill:#e1f5ff
    style B fill:#e1f5ff
    style C fill:#e1f5ff
    style D fill:#fff4e1
    style E fill:#fff4e1
    style F fill:#f0e1ff
    style G fill:#f0e1ff

Prerequisites

Before starting this module, you should have:

  • ✅ Completed Module 6 (Resource Implementation)
  • ✅ Understanding of resource CRUD operations
  • ✅ Familiarity with Terraform data sources
  • ✅ Go programming experience
  • ✅ API client integration knowledge

Time Commitment

  • Reading & Learning: 4-5 hours
  • Hands-on Lab: 1 hour
  • Practice Questions: 45 minutes
  • Total: ~6 hours

Key Concepts Preview

Data Source Interface

type DataSource interface {
    Metadata(context.Context, MetadataRequest, *MetadataResponse)
    Schema(context.Context, SchemaRequest, *SchemaResponse)
    Read(context.Context, ReadRequest, *ReadResponse)
}

Configure Interface

type DataSourceWithConfigure interface {
    DataSource
    Configure(context.Context, ConfigureRequest, *ConfigureResponse)
}

Read-Only Nature

  • No Create, Update, or Delete
  • Cannot modify infrastructure
  • Results cached during plan
  • Refreshed on each plan/apply

Module Goals

By completing this module, you’ll build production-ready data sources that:

  1. Query efficiently - Optimize API calls and filtering
  2. Handle errors gracefully - Clear messages for not-found scenarios
  3. Provide flexibility - Support multiple query patterns
  4. Validate inputs - Catch configuration errors early
  5. Document well - Clear usage examples and attribute descriptions

Success Criteria

You’ll know you’ve mastered this module when you can:

  • Explain when to use data sources vs. resources
  • Design effective data source schemas
  • Implement Read operations with error handling
  • Create flexible filtering mechanisms
  • Handle single vs. multiple result scenarios
  • Build data sources that work with complex queries
  • Write comprehensive tests for data sources
  • Apply data source best practices

What’s Next?

Ready to start? Let’s begin with data source basics!

Start: Data Source Basics →


Previous: ← Resource Practice

Last updated: June 30, 2026

Updated: