Selectors
When you have multiple Terraform blocks of the same type and label, you need to target them precisely. The selectors—index
, where
, and labels
—let you specify which block(s) you want to modify or remove, preventing ambiguity and accidental overwrites.
Tip: If you only have one block with a particular name or label, you usually don’t need a selector. However, as soon as you have more than one, or you want to filter them by attributes, selectors become crucial.
1. index
Use index
to pick the nth repeated block. For example, if you have three aws_instance
blocks all named main
, but with small differences, you can select the second one by using "index": 1
.
"update": {
"resource": {
"aws_instance": {
"main": [
{
"index": 1,
"attributes": {
"instance_type": "t2.micro"
}
}
]
}
}
}
- What Happens:
- The API looks at all
aws_instance.main
blocks. - Applies the
update
only to the second block in that array (arrays are zero-indexed internally).
- The API looks at all
Pros: Straightforward if you’re absolutely sure about the order.
Cons: If the order changes or new blocks are added, the index could point to the wrong block.
2. where
Use where
to match a key-value pair in the block’s attributes. This is more dynamic than using an index, since it depends on the actual content of the block rather than position.
"delete": {
"resource": {
"aws_instance": {
"main": [
{
"where": {
"instance_type": "t2.small"
}
}
]
}
}
}
- What Happens:
- The API checks all
aws_instance.main
blocks, looking for the one that has"instance_type" = "t2.small"
. - Deletes that block (assuming there’s exactly one match).
- The API checks all
Pros: Resilient to ordering changes.
Cons: Requires unique attribute values to avoid unintended matches.
3. labels
Use labels
when dealing with sub-blocks that have labels. For example, some resources include sub-blocks like:
provisioner "local-exec" {
command = "echo hello"
}
You can select these labeled sub-blocks with "labels": ["local-exec"]
.
"update": {
"blockTypes": {
"provisioner": [
{
"labels": ["local-exec"],
"attributes": {
"command": "echo updated"
}
}
]
}
}
- What Happens:
- Finds the
provisioner "local-exec"
block and updates its command.
- Finds the
Pros: Makes it easy to target sub-blocks that have a clear label.
Cons: Not all Terraform sub-blocks use labels (e.g., a simple ebs_block_device
block might not).
Combining Selectors
Sometimes, you need multiple selectors to narrow down to exactly the right block. For instance, consider a sub-block that has both a label and a unique attribute:
"set": {
"blockTypes": {
"provisioner": [
{
"labels": ["local-exec"],
"where": {
"command": "echo hello"
},
"attributes": {
"command": "echo final"
}
}
]
}
}
Here, you first find the labeled provisioner and then confirm that its command
attribute matches "echo hello"
. Only then do you set the command to "echo final"
.
Ambiguity Handling
- Multiple Matches: If you don’t provide a selector or it’s too vague (like
where
matches more than one block), the operation fails as ambiguous. - No Matches: The operation fails because nothing was found to
update
,delete
, etc. (except for theset
operation, which can create a block if none exists—but it still fails if multiple blocks match). - Just One Match: If a single block matches, the operation proceeds without complaint.
Best Practices for Selectors
- Use
where
for Highly Dynamic Configs
If blocks might appear in random orders or at random times, anchor your changes on a unique attribute. - Avoid
index
for Production
Unless you have a rock-solid guarantee about the ordering,index
can lead to surprises if someone adds or removes a block. - Label Sub-Blocks When Possible
If you’re defining sub-blocks likeprovisioner
in Terraform code, adding meaningful labels (like"local-exec", "remote-exec"
) makes them easier to target. - Combine Selectors for Extra Precision
A single attribute might not be unique enough—consider usingwhere
with multiple key-values (e.g.,{"device_name": "/dev/sdf", "encrypted": "true"}
).
Next Steps
- Learn how to use these selectors in tandem with multi-level structures in Nested Operations.
- Check out Advanced Usage for complex real-world scenarios.
- See the FAQ if you run into any issues with ambiguity or matching rules.