Cloud  /  Terraform

IaC Terraform 50 guides · updated 2026

Infrastructure as code done right — providers, state, reusable modules, and the workflow patterns that keep multi-cloud deployments sane in 2026.

terraform init

terraform init is always the first command you run in a Terraform project. It sets up the working directory by downloading providers, configuring the backend, and installing any referenced modules. Nothing else works until init completes successfully.


What terraform init Does

Terminal window
terraform init

Under the hood, init performs three distinct operations in sequence:

1. Backend Initialization

Configures where Terraform stores its state file. If using the default local backend, this creates a terraform.tfstate file in the working directory. For remote backends (S3, Terraform Cloud), this establishes the connection.

2. Provider Plugin Download

Downloads provider plugins required by required_providers blocks. Plugins are stored in .terraform/providers/ and are platform-specific binaries (different downloads for macOS ARM vs. Linux x86_64).

3. Module Installation

Downloads any external modules referenced with source pointing to a registry, git URL, or local path. Module code is cached in .terraform/modules/.


Output Explained

Terminal window
$ terraform init
Initializing the backend...
Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.
Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 5.50"...
- Installing hashicorp/aws v5.54.1...
- Installed hashicorp/aws v5.54.1 (signed, key ID 34365D9472D7468F)
Terraform has created a lock file .terraform.lock.hcl to record the provider
selections made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.
Terraform has been successfully initialized!

The Lock File: .terraform.lock.hcl

init creates or updates .terraform.lock.hcl, which records exact provider versions and checksums:

# .terraform.lock.hcl — ALWAYS commit this to git
provider "registry.terraform.io/hashicorp/aws" {
version = "5.54.1"
constraints = "~> 5.50"
hashes = [
"h1:bF6...", # Hash for current platform
"zh:abc...", # zh: hashes are canonical across platforms
]
}

By committing this file, you guarantee that every team member and CI/CD runner uses the same provider version, preventing “works on my machine” issues.


Key Flags

Terminal window
# Upgrade providers to latest within constraints
terraform init -upgrade
# Reconfigure backend (e.g., moved state file location)
terraform init -reconfigure
# Skip backend setup (useful for local testing without remote state)
terraform init -backend=false
# Pass backend config inline (avoids hardcoding in .tf files)
terraform init \
-backend-config="bucket=my-state-bucket" \
-backend-config="key=prod/terraform.tfstate" \
-backend-config="region=us-east-1"
# Non-interactive mode for CI pipelines
terraform init -input=false
# Specify directory
terraform init path/to/module

Backend Configuration Patterns

Local Backend (Default)

# No backend block needed — state lives in terraform.tfstate

S3 Backend

terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "environments/production/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-state-lock"
encrypt = true
}
}

Terraform Cloud Backend

terraform {
cloud {
organization = "my-org"
workspaces {
name = "production"
}
}
}

Avoid hardcoding backend details by providing them at init time:

# versions.tf — skeleton only
terraform {
backend "s3" {}
}
Terminal window
# backend.hcl — stored separately, not committed if sensitive
bucket = "my-terraform-state"
key = "production/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-state-lock"
Terminal window
terraform init -backend-config=backend.hcl

Common init Errors and Fixes

Error: No valid credential sources found

Error: configuring Terraform AWS Provider: no valid credential sources found

Fix: Configure AWS credentials via environment variables, ~/.aws/credentials, or IAM role.

Error: Backend configuration changed

Error: Backend configuration changed

Fix: Run terraform init -reconfigure to acknowledge the backend change.

Error: Could not retrieve the list of available versions

Error: Failed to query available provider packages

Fix: Check network connectivity; corporate proxies may need HTTPS_PROXY set.

Error: Module not found

Error: Module not installed

Fix: The module source changed or was added. Run terraform init again.


When to Re-run terraform init

SituationAction
New provider addedterraform init
Provider version changed in lock fileterraform init -upgrade
New module source addedterraform init
Backend configuration changedterraform init -reconfigure
New team member clones the repoterraform init
After git pull that adds modulesterraform init

.terraform/ Directory Structure

.terraform/
├── providers/
│ └── registry.terraform.io/
│ └── hashicorp/
│ └── aws/
│ └── 5.54.1/
│ └── darwin_arm64/ # Platform-specific binary
│ └── terraform-provider-aws_v5.54.1_x5
├── modules/
│ └── modules.json # Module source cache
└── terraform.tfstate # Backend state (if local)

Add .terraform/ to .gitignore — it contains binaries and should not be committed. The .terraform.lock.hcl file at the project root should always be committed.