Addresses and Attribute References

Scenario: An engineer runs a targeted state command against server.api, forgetting that a real Terraform address always needs the resource type and, for repeated resources, an instance key too - the command matches nothing and silently does nothing.

Every resource Terraform manages has a unique address, built from its type, its local name, and (if it was created with count or for_each, covered next) an instance key: fakecloud_server.api for a single instance, fakecloud_server.api[0] for the first instance of a counted resource, or fakecloud_server.api["blue"] for a named instance created with for_each. This address is exactly what you use both to reference a resource's attributes elsewhere in your configuration (fakecloud_server.api.address) and to target it directly with CLI state commands.

A reference - writing fakecloud_network.app.id inside another resource's block - does two things at once: it substitutes the real value in, and it tells Terraform "this resource depends on that one," contributing an edge to the dependency graph you learned about in Module 1. Because some attributes (like a provider-generated ID) don't exist until the object is actually created, a reference to such an attribute may show as unknown during planning - normal and expected. A subtle but important practice: never copy a resource's ID into a plain string or variable just because it's convenient. A copied value has no ongoing connection to its source - if the source object gets recreated with a new ID, your copy is now silently wrong, whereas a genuine reference always resolves to the current, correct value and correctly reorders operations around it.

Analogy: A resource address is a library's call number - a precise, structured pointer to one specific book on one specific shelf. An attribute reference is a citation that always points to the live book; copying a sentence out of it into your own notes instead loses the live connection - if the book gets revised, your copied sentence doesn't update with it.

A worked configuration

resource "fakecloud_network" "app" { name = "app" }
resource "fakecloud_server" "api" {
  name       = "api"
  network_id = fakecloud_network.app.id
}
output "api_address" { value = fakecloud_server.api.address }

Stable, meaningful resource addresses make later state operations and refactors dramatically safer, because the address itself becomes part of what identifies the object in state. Here's the trap: simply renaming a resource's local label (resource "fakecloud_server" "api" to "web") changes its Terraform address even though nothing about the real provider-side object changed at all - and by default Terraform reads that as "the old address is gone, plan a destroy; a new address appeared, plan a create," which means an innocent rename can queue up real destroy-and-recreate operations. The fix, covered properly in a later module, is to pair any address rename with a moved block so Terraform understands it's the same object under a new name.

Common mistakes in production

Goal: Treat the plan as a change contract: understand every create, update, replacement, and destroy before approving it. Reinforce this lesson in the tf-dependency-ordering Terraform lab. Open /labs/terraform and choose slug tf-dependency-ordering; the lab runs real Terraform against the offline FakeCloud provider.