Skip to content
Infrastructure as Code iac providers 4 min read

Configuring Providers

A provider is the plugin Terraform uses to talk to a platform’s API — AWS, Azure, GCP, Kubernetes, GitHub, and hundreds more. Before Terraform can create a single resource it needs a configured provider: the credentials, the region or project, and the API endpoints to target. The provider block is where you supply that configuration, and getting it right is the foundation every resource in your configuration depends on. This page walks through declaring and configuring provider blocks, the difference between default and explicit configuration, and how Terraform resolves which provider a resource uses. Everything here applies equally to OpenTofu, which shares Terraform’s HCL2 syntax and provider protocol.

The provider block

A provider block configures a single instance of a provider. The block label is the provider’s local name — the same name resources reference through their type prefix (an aws_instance belongs to the aws provider). Inside the block you set provider-specific arguments such as region and profile.

provider "aws" {
  region  = "us-east-1"
  profile = "production"
}

resource "aws_s3_bucket" "assets" {
  bucket = "devcraftly-static-assets"
}

The region tells the AWS provider which regional endpoint to send requests to, and profile selects a named credentials profile from your shared AWS config files. With this block in place, the aws_s3_bucket resource is created in us-east-1 using the production profile’s credentials.

Provider configuration is not state. Changing region or profile does not migrate existing resources — it changes where new and refreshed operations are sent. Moving a resource between regions is a destroy-and-recreate operation.

What provider configuration supplies

Provider arguments fall into a few broad categories. Most providers expose all of these, though the exact argument names differ.

CategoryPurposeAWS example
CredentialsAuthenticate API requestsprofile, access_key, assume_role
LocationSelect the region/project/zoneregion
EndpointsOverride API URLs (testing, GovCloud, LocalStack)endpoints {}
BehaviorTune retries, tags, validationdefault_tags, max_retries

You should almost never hardcode long-lived credentials in a provider block. Prefer environment variables, named profiles, or short-lived role assumption — see Provider authentication for the full picture. The example below configures location and behavior while leaving credentials to the surrounding environment.

provider "aws" {
  region      = "eu-west-1"
  max_retries = 10

  default_tags {
    tags = {
      Environment = "staging"
      ManagedBy   = "terraform"
    }
  }
}

default_tags automatically applies the given tags to every taggable resource this provider manages — a clean way to enforce tagging standards without repeating yourself.

Default versus explicit configuration

A provider block with no alias argument is the default configuration for that provider. Any resource of a matching type uses it automatically — you do not need to wire anything up. This is the common case and keeps configurations terse.

# Default aws provider — every aws_* resource uses this automatically.
provider "aws" {
  region = "us-east-1"
}

When you need more than one configuration of the same provider — for example deploying to two regions, or to two accounts — you give the additional blocks an alias and reference them explicitly with the provider meta-argument on each resource. That pattern is covered in depth in Provider aliases.

provider "aws" {
  alias  = "west"
  region = "us-west-2"
}

resource "aws_s3_bucket" "dr" {
  provider = aws.west
  bucket   = "devcraftly-dr-backups"
}

Without the provider = aws.west line, the aws_s3_bucket.dr resource would fall back to the default (unaliased) aws provider.

Using variables for configuration

Hardcoding a region works for a single environment, but real configurations vary it per workspace. Drive provider arguments from input variables so the same code deploys to dev, staging, and prod.

variable "aws_region" {
  type        = string
  description = "AWS region to deploy into."
  default     = "us-east-1"
}

provider "aws" {
  region = var.aws_region
}

Provider blocks can only reference values that are known at plan time — input variables, locals, and other provider-independent expressions. You cannot use a resource attribute (a value computed during apply) to configure a provider. Doing so produces a Provider configuration not present or cycle error.

Initializing after configuration

Adding or changing a provider requires terraform init (or tofu init) so the corresponding plugin is downloaded and recorded. After that, plan and apply use the configured settings.

terraform init
terraform plan

Output:

Initializing provider plugins...
- Finding hashicorp/aws versions matching ">= 5.0.0"...
- Installing hashicorp/aws v5.82.2...
- Installed hashicorp/aws v5.82.2 (signed by HashiCorp)

Terraform has been successfully initialized!

Terraform will perform the following actions:

  # aws_s3_bucket.assets will be created
  + resource "aws_s3_bucket" "assets" {
      + bucket = "devcraftly-static-assets"
      + region = "us-east-1"
      + arn    = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

The region = "us-east-1" in the plan output confirms the provider configuration was picked up. If the region is wrong, fix the provider block before running apply.

Best Practices

  • Set region (or the equivalent location argument) explicitly rather than relying on ambient environment defaults, so the target is visible in the configuration.
  • Drive provider arguments from input variables to make the same code reusable across environments.
  • Keep credentials out of provider blocks — use profiles, environment variables, or assume_role instead of hardcoded keys.
  • Use default_tags (AWS) or its provider equivalent to enforce consistent metadata across all resources.
  • Use a single default provider per platform where possible; reach for aliases only when you genuinely need multiple regions or accounts.
  • Run terraform init after any provider change, and review the plan output to confirm the resolved location and settings before applying.
Last updated June 14, 2026
Was this helpful?