Skip to main content
RunBook Academy

TerraformV · The Terraform WorkflowInit

terraform init in Depth

Intermediate⏱ ~14 min🧪 Lab requiredbashterraform

What you'll learn

  • Explain what `terraform init` does and what it does not do
  • Describe the dependency lock file and its role in reproducibility
  • Recognise common init failure modes and how to recover
  • Apply the right init flags for the right context

Prerequisites

Verified against Terraform CLI 1.9.x · OpenTofu 1.7.x · HCL 2.0 · bpg/proxmox provider 0.66+ · hashicorp/local provider 2.5+ · hashicorp/null provider 3.2+ · hashicorp/random provider 3.6+ · hashicorp/http provider 3.4+ · Ubuntu 24.04 LTS · Debian 12 (Bookworm) · 2026-08-12

Not yet marked complete on this device.

terraform init is the step that prepares a working directory for use. It is the only step that talks to the provider registry or the module sources. It is the source of subtle production surprises when the lock-file contract is violated. This lesson covers what init does, what the dependency lock file is, and how to recover from common init failures.

What init does in order

terraform init

1. Read configuration
   - Look for `terraform { required_providers, backend }` blocks

2. Resolve provider sources
   - registry.terraform.io
   - Internal mirrors
   - Local filesystem paths

3. Download providers
   - Hashicorp-validated providers from the registry
   - Checksum-verified against the lock file

4. Resolve module sources
   - registry, git, github, hg, s3, gcs, local

5. Download modules

6. Initialise the backend
   - Local: create terraform.tfstate
   - Remote: negotiate with the backend (S3, GCS, Consul, etc.)

7. Write or update .terraform.lock.hcl

8. Create the .terraform/ working directory
   - provider plugins
   - module downloads
   - backend configuration

Each step is conditional. A terraform init on a simple configuration with no providers and no modules may download nothing and create a minimal .terraform/ directory.

The dependency lock file

The .terraform.lock.hcl file is the reproducibility contract:

# This file is maintained automatically by "terraform init".
# Manual edits may be lost - proceed with caution!

provider "registry.terraform.io/hashicorp/local" {
  version = "2.5.1"
  hashes = [
    "h1:abc123...",
    "zh:def456...",
  ]
}

provider "registry.terraform.io/hashicorp/random" {
  version = "3.6.0"
  hashes = [
    "h1:...",
    "zh:...",
  ]
}

The lock file records:

  • The exact version of each provider.
  • The hashes of the provider binary, verified against the registry.

The lock file is typically committed to source control. The exception is local-only or gitignored working directories.

The lock file is what defends the installation of the configuration. Without a lock file, every terraform init may download a different provider patch version, and the underlying provider API behaviour may differ.

When init fails

The common init failure modes:

Provider download failure

Error: Failed to install provider
  Plugin reinitialization required. Please run "terraform init".

The provider cannot be downloaded. Causes:

  • The provider source is unreachable (network, registry outage).
  • The provider version is not in the registry.
  • The providers checksum does not match the lock file.

Recovery:

# Verify the source is reachable
curl -fsSL https://registry.terraform.io/.well-known/terraform.json

# Bypass the lock file (if you are sure of the new version)
terraform init -upgrade

# Reset the lock file and re-download
rm -rf .terraform .terraform.lock.hcl
terraform init

Backend initialisation failure

Error: Failed to get existing workspaces: S3 bucket does not exist

The backend cannot be initialised. Causes:

  • The backend credentials are missing or invalid.
  • The backend resource (e.g. S3 bucket) does not exist.
  • The backend configuration has changed since the last init.

Recovery:

# Run with verbose logging to see the underlying error
TF_LOG=info terraform init

# Reconfigure the backend (does not re-download providers)
terraform init -reconfigure

# Migrate the backend (see Part XXXV)
terraform init -migrate-state

Module source failure

Error: Failed to download module

The module source cannot be reached. Causes:

  • The Git source is unreachable.
  • The module version does not exist in the source.
  • The module source has been removed.

Recovery:

# Verify the source is reachable
git ls-remote https://github.com/example/terraform-module

# Reinitialise modules (does not re-download providers)
terraform get -update

Lock-file mismatch

Error: Failed to install provider
  Lock file does not match the installed providers.

The lock files recorded hashes do not match the local .terraform/ directory. Causes:

  • The lock file was updated, but terraform init was not run.
  • The .terraform/ directory was partially deleted.
  • The provider binary was modified.

Recovery:

# Reinitialise from the lock file
terraform init -upgrade

# Or reset and re-download
rm -rf .terraform
terraform init

Init flags

A few flags worth knowing:

# Upgrade providers within the constraints
terraform init -upgrade

# Reconfigure the backend, do not re-download providers
terraform init -reconfigure

# Migrate state to a new backend without losing state
terraform init -migrate-state

# Skip provider backend initialisation (rare; useful for offline analysis)
terraform init -backend=false

# Skip provider download (useful for syntax-only checks)
terraform init -provider=false

# Skip module download
terraform init -module=false

The .terraform/ directory

The .terraform/ directory is the working cache. It contains:

  • providers/registry.terraform.io/.../ — the provider binaries.
  • modules/... — the downloaded modules.
  • environment — a small file recording the working directory.

The .terraform/ directory is not committed to source control (.gitignore excludes it). It is regenerated by terraform init.

The .terraform/ directory should be considered build cache, not state. It is safe to delete and rebuild. The state is in the backend.

Provider plugin cache

For teams with many engineers, the provider-plugin-cache-dir CLI config setting avoids re-downloading providers across workspaces:

# ~/.terraformrc
provider_installation {
  methods {
    - filesystem_mirror {
      path = "/usr/local/share/terraform/plugins"
      include = ["registry.terraform.io/*/*"]
    }
  }
}

When configured, every terraform init checks the local mirror before reaching the registry. This is a meaningful speedup for large workspaces and a defence against registry outages.

What init does not do

  • Does not validate the configuration. terraform validate does that.
  • Does not compute a plan. terraform plan does that.
  • Does not apply the configuration. terraform apply does that.
  • Does not touch the state. Init does not change state.
  • Does not download providers without a required_providers block. The configuration must declare which providers to use.

A production init workflow

# CI: always run init with the lock file
terraform init -input=false

# CI: validate the lock file
terraform providers lock -platform=linux_amd64 -platform=darwin_amd64 -platform=darwin_arm64

# Local: when changing versions
terraform init -upgrade

# Local: when changing backend
terraform init -migrate-state

The terraform providers lock command is the CI gate for the lock file. It re-records the hashes for the specified platforms and fails if the recorded hashes do not match the available binaries.

What comes next

The next lesson is terraform plan in depth. The plan is the operational artefact; the course has already covered it holistically, and the next lesson is a deeper dive into the plan output.

Knowledge check · 7 questions

  1. Q1. What is the role of terraform fmt?

  2. Q2. What is the role of terraform validate?

  3. Q3. What is the role of terraform init?

  4. Q4. terraform plan modifies the real world.

  5. Q5. Which of the following are part of the safe workflow? (Select all that apply.)

  6. Q6. What does terraform show do?

  7. Q7. A team runs terraform plan and sees no changes. The apply also shows no changes. The real world has drifted. What should they do?

Passing score: 75%. Answers are checked in this browser.