Terraform Configuration · Topic 1 of 4
Resources, Data Sources and References
Terraform Associate 004: resource versus data blocks, reference syntax for attributes, count and for_each instances, splat expressions and data reads.
- 5 min
- Resource blocks manage objects; data blocks only read existing objects.
- Data source addresses always start with
data.; resource addresses do not have a prefix. - The address pattern is
TYPE.NAME.ATTRIBUTE, with an index such as[0]or["key"]for count and for_each instances.
What it is
A resource block declares an infrastructure object that Terraform creates, updates and destroys. A data block (a data source) only reads information about something that already exists, such as an image ID or an existing network.
Both blocks expose attributes. You connect blocks by referring to those attributes, and every reference also tells Terraform which block must be handled first.
How it works
Resource blocks and data blocks
A block starts with its kind, then a type label from the provider, then a local name you choose. The type and name together form the address.
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"]
}
resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id
instance_type = "t3.micro"
}
Here the data source looks up an image and the resource uses its id. Terraform never creates or deletes the image; it only reads it.
| Feature | resource block | data block |
|---|---|---|
| Purpose | Create and manage an object | Read an existing object |
| Address | aws_instance.web | data.aws_ami.ubuntu |
| Lifecycle | Create, update, destroy | Read only |
| Shown in plan as | create, update, replace, destroy | read (when deferred to apply) |
| Removed by terraform destroy | Yes | No, nothing to destroy |
Data sources are normally read during planning. If a data source depends on a value that is not known until apply, Terraform defers the read to the apply step.
The local name only needs to be unique within its kind and type in the module. A resource and a data source can share the same type and name because the data. prefix keeps their addresses apart.
Reference syntax
Terraform refers to named values with a fixed pattern.
| What you refer to | Syntax |
|---|---|
| Resource attribute | aws_instance.web.private_ip |
| Data source attribute | data.aws_ami.ubuntu.id |
| Input variable | var.region |
| Local value | local.common_tags |
| Child module output | module.network.vpc_id |
A resource exposes the arguments you set plus attributes the provider computes, such as id or arn. Computed attributes are "known after apply" in a plan until the object exists. The same addresses are used on the command line, for example terraform plan -target=aws_instance.web to target one resource in exceptional cases.
Instances from count and for_each
When a resource uses count, each instance has a number index starting at 0. With for_each, each instance has the map key or set value as its index.
resource "aws_instance" "app" {
count = 3
ami = data.aws_ami.ubuntu.id
instance_type = "t3.micro"
}
output "first_ip" {
value = aws_instance.app[0].private_ip
}
| Meta argument | Instance address | Index type |
|---|---|---|
| count | aws_instance.app[0] | Number |
| for_each | aws_instance.app["blue"] | String key |
Splat expressions
A splat expression collects one attribute from every instance into a list. aws_instance.app[*].id returns a list of all three IDs.
The splat works on resources that use count. For a resource that uses for_each, the instances form a map, so you use a for expression instead, for example [for i in aws_instance.app : i.id].
Cross-resource references create order
A reference such as subnet_id = aws_subnet.main.id makes an implicit dependency. Terraform builds its dependency graph from these references, creates the subnet first, then the instance that uses it.
This is why most configurations need no explicit ordering at all. Page 3 of this chapter covers depends_on for the cases where no reference exists.
How the exam asks about this
- "You need the ID of an existing VPC that another team manages." Use a data block; a resource block would try to create a new VPC.
- "Which expression returns the IDs of all instances created with count = 3?"
aws_instance.app[*].id, the splat expression. - "How do you refer to an output named vpc_id from a module called network?"
module.network.vpc_id.
What to remember for the exam
- Resource blocks manage objects; data blocks only read existing objects.
- Data source addresses always start with
data.; resource addresses do not have a prefix. - The address pattern is
TYPE.NAME.ATTRIBUTE, with an index such as[0]or["key"]for count and for_each instances. [*]collects one attribute from every instance into a list.- Every reference to another block creates an implicit dependency and sets the order of operations.
- Computed attributes such as
idshow as "known after apply" in a plan for objects not yet created.
terraform destroy removes managed resources only. It never deletes the object a data source reads, because Terraform does not manage that object.
Common mistakes
Using a resource block to look something up. Declaring resource "aws_vpc" for a network that already exists tells Terraform to create a second one. Reading an existing object needs a data block.
Dropping the data prefix. Writing aws_ami.ubuntu.id when the block is a data source fails because no such resource exists. The correct reference is data.aws_ami.ubuntu.id.
Indexing for_each instances by number. Instances created with for_each are keyed by strings, so aws_instance.app[0] is wrong. Use the key, such as aws_instance.app["blue"].
Check yourself
What is the difference between a resource block and a data block?
A resource block creates, updates and destroys an object that Terraform manages. A data block only reads an existing object so its attributes can be used elsewhere.
How do you refer to the private IP of the second instance of a resource that uses count?
Use the zero-based index,
aws_instance.app[1].private_ip.What does a reference between two resources do besides passing a value?
It creates an implicit dependency, so Terraform creates the referenced resource before the one that refers to it.
Topic 1 of 4 in Terraform Configuration
Test yourself on Terraform Configuration
The full HashiCorp Terraform Associate 004 question bank has 600 questions, with timed practice exams and an explanation for every answer.
This study guide is independent and is not affiliated with, endorsed by, or sponsored by HashiCorp. Vendor names, certification names and exam codes are trademarks of their respective owners and are used for identification only.