Sharing Data Across States
Scenario: A network team's state exports its entire resource object as one convenient output, and every downstream consumer of that output ends up tightly coupled to the provider's internal schema - while also, as a side effect, gaining visibility into the network team's whole state snapshot.
Separate states (across teams, environments, or services) sometimes genuinely need to share a narrow integration fact with each other - most commonly something like "what's the ID of the shared network I should attach to." The built-in terraform_remote_state data source reads another state's outputs directly, which sounds narrow and safe, but the important caveat is that in practice it commonly requires - and grants - read access to that state's entire snapshot, not just the specific output you meant to read. If that upstream state contains anything sensitive, terraform_remote_state access is effectively a much bigger permission grant than "share one integration value" implies.
HCP Terraform's tfe_outputs data source is a narrower alternative purpose-built for exposing just outputs, with tighter intended scope than a full state read. Other common patterns sidestep state-sharing entirely: publishing a value to a dedicated parameter store, a DNS record, or a provider-native data source that the consuming state queries independently. Whatever mechanism you choose, be deliberate about direction: design your states as a one-way dependency graph (network → services → applications, say) and actively avoid cycles, where state A depends on an output from state B while B also depends on an output from A - that's structurally undecidable, similar to the acyclic-graph requirement you learned about back in Module 1.
Analogy: Independent Terraform states are like separate bounded departments in a company. A healthy cross-department relationship shares a documented, narrow public API - a specific report, a specific approved data feed - not a standing copy of the neighboring department's entire private database, which is effectively what a broad terraform_remote_state read grants if you're not careful about what that upstream state actually contains.
A worked configuration
data "terraform_remote_state" "network" {
backend = "remote"
config = { workspace = "network-prod" }
}
locals { network_id = data.terraform_remote_state.network.outputs.network_id }
Minimize what any given state exposes through outputs in the first place, and think about classification the same way you did with sensitive outputs in Module 4 - if an upstream state's outputs are ever going to be readable by a totally different team's Terraform run, treat everything in that state as something that team could potentially see. Run triggers (queuing a downstream run when an upstream one completes) can help sequence work across states, but they don't remove the underlying architectural coupling - any change to a shared value still needs coordination and, often, a compatibility window while consumers catch up.
Common mistakes in production
- Using
terraform_remote_stateto share one small integration value without realizing it commonly grants visibility into the entire upstream state snapshot, not just that one output. - Creating a circular dependency between two states (each reading an output from the other) - this is structurally unresolvable, the same way a dependency cycle within one configuration would be.
Goal: Treat the plan as a change contract: understand every create, update, replacement, and destroy before approving it. Reinforce this lesson in the tf-cross-state-outputs Terraform lab. Open/labs/terraformand choose slugtf-cross-state-outputs; the lab runs real Terraform against the offline FakeCloud provider.