What are providers in Terraform, and how does the provider plugin model work?
Quick Answer
A provider is a plugin that translates HCL resource blocks into API calls for a specific platform (AWS, Azure, GCP, Kubernetes, Datadog, etc.), exposing that platform's resources and data sources. `terraform init` downloads the provider binaries declared in a `required_providers` block (pinned by source and version constraint) into `.terraform/`, and a lock file (`.terraform.lock.hcl`) records exact versions/checksums for reproducible installs. Terraform's core engine has no built-in knowledge of any cloud — everything platform-specific lives in providers, which is what makes Terraform multi-cloud.
Detailed Answer
Terraform's core binary knows nothing about AWS, Azure, GCP, Kubernetes, or any other platform. All of that platform-specific knowledge lives in providers — separate plugin binaries that Terraform Core talks to over a well-defined RPC protocol.
Declaring a provider
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
sourceis the provider's registry address (<namespace>/<name>, defaulting to the public Terraform Registry).versionis a constraint (~> 5.0means "5.x, but not 6.0"), preventing an unreviewed major-version upgrade from silently changing behavior.
What terraform init does with this
- Resolves the version constraint against what's available in the registry (or a private/mirrored registry).
- Downloads the matching provider binary into
.terraform/providers/. - Records the exact version and a checksum of the binary in
.terraform.lock.hcl— this lock file gets committed to git so every teammate and every CI run installs byte-for-byte the same provider, the same waypackage-lock.jsonpins npm dependencies.
How the plugin model works at runtime
- Each provider exposes a schema describing every resource type and data source it supports (
aws_instance,aws_s3_bucket,google_compute_instance, etc.), including which arguments exist, their types, and whether changing them forces resource replacement. - When you run
plan/apply, Terraform Core spawns the provider as a subprocess and communicates over gRPC: "here's the desired config for this resource, here's the last known state — tell me what changed and then perform the create/update/destroy." - The provider is what actually calls the cloud's REST API (e.g., the AWS SDK) under the hood.
Why this design matters
Because everything platform-specific is isolated behind this plugin boundary, the same Terraform language, workflow, and state model works identically whether you're managing AWS resources, a Kubernetes cluster, a Datadog monitor, or a GitHub repository — you just declare a different provider. It's also why community and third-party providers can exist for almost any API with a stable schema, without ever touching Terraform's core codebase.