2.2.2. The required_providers Block
💡 First Principle: Declaring which providers exist (required_providers) is separate from configuring how they behave (provider blocks) — keeping the dependency declaration distinct from runtime settings is what lets Terraform resolve and lock versions before it ever configures anything.
required_providers lives inside the terraform block and answers "what plugins does this configuration depend on, and at what versions?" The provider block answers "how should that plugin be configured at runtime?" They work together but have different jobs:
| Concern | Where it lives | What it does |
|---|---|---|
| Which provider + version | required_providers (inside terraform block) | Declares source address and version constraint for init to resolve |
| How the provider behaves | provider "name" block | Sets region, credentials, endpoints, aliases |
Declaring the source explicitly matters because provider type names (like aws) aren't globally unique — the full source address (hashicorp/aws) disambiguates which published provider you mean, especially for community or partner providers.
⚠️ Exam Trap: A configuration can reference a provider implicitly (by using aws_ resources) but still needs the source declared in required_providers for non-HashiCorp or ambiguously named providers. The exam may test that required_providers is the authoritative place to pin both source and version.
Reflection Question: You can configure a provider with a provider block alone in simple cases — so why does HashiCorp recommend always declaring it in required_providers too?