Resources vs Data Sources

Scenario: Two separate teams each declare the same shared company network as a resource in their own independent Terraform state, and both genuinely believe they are the one responsible for its lifecycle.

You've used resource blocks throughout this track, but Terraform has a second, equally important block type: data. The difference is about ownership, and getting it right prevents exactly the incident above. A resource block means "Terraform should create this object if it doesn't exist, and manage its lifecycle from now on - including destroying it if the block is removed." A data block means "this object already exists, owned by someone or something else; just read its current attributes so I can use them." A data source has no create/update/destroy behavior at all - it's a read-only lookup.

Critically, this is a statement about who owns the lifecycle, not about whether the object happens to already exist right now: perfectly real, already-existing infrastructure can still become a Terraform-managed resource through import (a whole module later in this track). The rule of thumb is simple: if this configuration should be allowed to destroy the object, it's a resource; if it should only ever read from it, it's a data source. Reads from a data block usually happen early, during the plan's refresh step, but if the data source's own arguments depend on another resource's output, Terraform correctly defers that lookup until apply time, once the dependency is known.

Analogy: A resource is an asset entry on your own company's inventory ledger - you bought it, you're responsible for it, you can dispose of it. A data source is a directory lookup - looking up a courthouse's address and opening hours does not make you its owner, and you certainly can't order it demolished.

A worked configuration

data "fakecloud_network" "shared" {
  name = "platform-network"
}
resource "fakecloud_server" "api" {
  name       = "api"
  network_id = data.fakecloud_network.shared.id
}

Ambiguous lookups are a genuine production hazard: a data block that searches by a loose filter (say, a common tag) rather than a stable unique name or ID can silently match the wrong object if a second one is created later with a similar tag - and because it's just a read, Terraform won't warn you, it will happily wire your server to whatever network the filter matched. Query by the most specific stable identifier available, and document in a comment or README which team or state actually owns each shared object your data blocks depend on.

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-data-source-discovery Terraform lab. Open /labs/terraform and choose slug tf-data-source-discovery; the lab runs real Terraform against the offline FakeCloud provider.