02 · The Provider Model
Terraform itself does not know anything about AWS, GCP, GitHub, Datadog, or Kubernetes. It is a generic engine for resource lifecycle management. Providers are the plugins that translate Terraform's resource model into real API calls.
This is the architecture that lets a single tool manage cloud infrastructure, DNS records, GitHub repositories, database users, and Slack channels with the same workflow.
What a Provider Is
A provider is a binary plugin that:
- Declares the resources it manages (e.g.,
aws_instance,github_repository) - Implements CRUD operations for each resource (create, read, update, delete)
- Handles authentication with the underlying API
When you run terraform init, Terraform downloads the required providers from the Terraform Registry and stores them in .terraform/. They are versioned, cryptographically verified, and pinned in .terraform.lock.hcl.
Declaring Providers
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
github = {
source = "integrations/github"
version = "~> 6.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
provider "github" {
owner = "my-org"
token = var.github_token
}
The terraform block pins provider versions. The provider block configures them. You can have multiple configurations of the same provider (e.g., two AWS providers for different regions) using provider aliases.
The Resource Abstraction
Every resource follows the same interface regardless of provider:
The provider handles everything below this interface: which API endpoint to call, how to parse the response, what to do on update vs. replace. From Terraform's perspective, an aws_instance and a github_repository are both just "resources" — they have attributes, they can be created and destroyed, and their state is tracked.
This uniformity means the Terraform workflow (init → plan → apply) works identically across all providers.
The Terraform Registry
The Terraform Registry is the central hub for providers and modules. The breadth of available providers is one of Terraform's most significant advantages:
- Cloud: AWS, GCP, Azure, DigitalOcean, Oracle
- SaaS APIs: GitHub, GitLab, Datadog, PagerDuty, Cloudflare, Fastly
- Databases: PostgreSQL, MySQL, MongoDB Atlas, Snowflake
- Security: HashiCorp Vault, AWS IAM, OPA
- Kubernetes: manages Kubernetes resources directly from Terraform
- Internal: any team can write a custom provider for internal APIs
This means the principle of Everything as Code can extend to your entire operational stack — not just cloud VMs, but DNS records, monitoring alerts, GitHub settings, and user access controls.
Provider vs. Resource vs. Data Source
Three distinct concepts within a provider:
Resource: manages the lifecycle of an infrastructure object.
Data source: reads existing infrastructure without managing it. Useful for referencing resources created outside Terraform, or resources managed by a different Terraform configuration.
Output: exposes values from a configuration for use by other configurations or for display.
Provider Versioning
Provider versions follow semantic versioning. The ~> 5.0 constraint means "5.x but not 6.0" — accept patch and minor updates, but not breaking major version changes.
The .terraform.lock.hcl file records the exact version and checksum used. Commit this file. It ensures that everyone on the team (and CI/CD) uses exactly the same provider version, preventing subtle behaviour differences between environments.
provider "registry.terraform.io/hashicorp/aws" {
version = "5.31.0"
constraints = "~> 5.0"
hashes = [
"h1:...",
]
}
Providers Are Not Magic
Providers are limited to what the underlying API supports. If the API is eventually consistent, Terraform may see a resource as created before it's actually ready. If the API doesn't support updates to a field, Terraform must destroy and recreate the resource.
Understanding your provider's limitations — what's immutable, what triggers a replace, what the API rate limits are — is as important as understanding Terraform itself.