What are providers in Terraform, and how does the provider plugin model work?

4 minbeginnerterraformprovidersplugins

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"
}
  • source is the provider's registry address (<namespace>/<name>, defaulting to the public Terraform Registry).
  • version is a constraint (~> 5.0 means "5.x, but not 6.0"), preventing an unreviewed major-version upgrade from silently changing behavior.

What terraform init does with this

  1. Resolves the version constraint against what's available in the registry (or a private/mirrored registry).
  2. Downloads the matching provider binary into .terraform/providers/.
  3. 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 way package-lock.json pins 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.

Related Resources