Data Sources
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
- Data Source Basics (20 min)
- What are data sources
- Resources vs. data sources
- Data source interfaces
- When to use data sources
- Common patterns
Implementation
- Data Source Schema (25 min)
- Schema design principles
- Required vs. optional attributes
- Computed attributes
- Filter blocks
- Validation
- Data Source Read (30 min)
- Read operation implementation
- Querying APIs
- Error handling
- Setting computed values
- Not found scenarios
- Data Source Filtering (30 min)
- Filter patterns
- Multiple filter criteria
- Tag filtering
- Name patterns
- Complex queries
- Handling Lists (25 min)
- Multiple results
- Single vs. list data sources
- Most recent patterns
- Sorting and limiting
- Error handling
Practice
- Data Sources Lab (60 min)
- Build complete data sources
- Single result lookup
- Filtered queries
- List handling
- Testing
- 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:
- Query efficiently - Optimize API calls and filtering
- Handle errors gracefully - Clear messages for not-found scenarios
- Provide flexibility - Support multiple query patterns
- Validate inputs - Catch configuration errors early
- 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!
Previous: ← Resource Practice
Last updated: June 30, 2026