Composition and Provider Passing

Scenario: A child module embeds provider credentials and cannot be reused across accounts or tested safely.

Provider configurations should normally live in the root and flow into children. A child declares provider requirements; aliases are explicitly mapped when it needs multiple configurations. Prefer flat composition where the root wires focused modules together through outputs and inputs. Deep nesting hides dependencies and makes replacement blast radius hard to see.

Analogy: The root module is an orchestra conductor: sections remain reusable, while the conductor selects performers and coordinates their outputs.

A worked configuration

module "certificate" {
  source = "./modules/certificate"
  providers = { fakecloud = fakecloud.primary }
  domain     = module.service.domain
}

Avoid passing whole resource objects merely for convenience; publish minimal stable outputs. That reduces coupling to provider schema and allows internal refactors without forcing every consumer to change.

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