Skip to main content

Selectors

When you have multiple Terraform blocks of the same type and label, you need to target them precisely. The selectorsindex, 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).

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).

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.

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 the set 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

  1. Use where for Highly Dynamic Configs
    If blocks might appear in random orders or at random times, anchor your changes on a unique attribute.
  2. 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.
  3. Label Sub-Blocks When Possible
    If you’re defining sub-blocks like provisioner in Terraform code, adding meaningful labels (like "local-exec", "remote-exec") makes them easier to target.
  4. Combine Selectors for Extra Precision
    A single attribute might not be unique enough—consider using where 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.