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
In a nutshell
  • 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.

Data sourcereads existing objectReferencedata.TYPE.NAME.attrResourcecreates and manages objectStatetracks the managed object

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.

Featureresource blockdata block
PurposeCreate and manage an objectRead an existing object
Addressaws_instance.webdata.aws_ami.ubuntu
LifecycleCreate, update, destroyRead only
Shown in plan ascreate, update, replace, destroyread (when deferred to apply)
Removed by terraform destroyYesNo, 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 toSyntax
Resource attributeaws_instance.web.private_ip
Data source attributedata.aws_ami.ubuntu.id
Input variablevar.region
Local valuelocal.common_tags
Child module outputmodule.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 argumentInstance addressIndex type
countaws_instance.app[0]Number
for_eachaws_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.

aws_vpc.mainvpc_idaws_subnet.mainsubnet_idaws_instance.web

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 id show as "known after apply" in a plan for objects not yet created.
Watch out

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.