Skip to content
Infrastructure as Code iac workflow 5 min read

terraform init

terraform init is the first command you run in any new or freshly cloned Terraform configuration. It prepares the working directory by downloading the providers your code references, installing any modules, and configuring the backend that stores your state. Until you run it, no other command (plan, apply, validate) will work, because Terraform has no provider plugins to talk to and no idea where state lives. It is safe to run repeatedly and is idempotent — running it on an already-initialized directory simply confirms everything is in place.

What init actually does

A single init performs several distinct steps in order. Understanding them makes the output far easier to read and the failures far easier to debug.

StepWhat happensWhere it lands
Backend initReads the backend block, prompts for credentials, configures remote/local state.terraform/terraform.tfstate (backend config cache)
Module installDownloads module sources (registry, Git, local paths).terraform/modules/
Provider installResolves version constraints and downloads provider plugins.terraform/providers/
Lock fileRecords exact provider versions and checksums.terraform.lock.hcl

Consider a minimal AWS configuration:

terraform {
  required_version = ">= 1.5"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.40"
    }
  }

  backend "s3" {
    bucket       = "acme-tfstate-prod"
    key          = "network/terraform.tfstate"
    region       = "us-east-1"
    use_lockfile = true
  }
}

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

resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_hostnames = true

  tags = {
    Name = "main-vpc"
  }
}

Running init in this directory produces:

terraform init

Output:

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.40"...
- Installing hashicorp/aws v5.42.0...
- Installed hashicorp/aws v5.42.0 (signed by HashiCorp)

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it 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!

OpenTofu users run the identical command as tofu init. The behavior, flags, and .terraform.lock.hcl format are compatible, so the rest of this page applies to both tools.

The .terraform directory and lock file

After init, two artifacts appear:

  • .terraform/ — a local cache containing downloaded providers, installed modules, and the resolved backend configuration. This directory is machine-specific and disposable. Add it to .gitignore; never commit it.
  • .terraform.lock.hcl — the dependency lock file. It pins the exact provider versions and their checksums (including per-platform hashes) so every teammate and your CI pipeline get bit-for-bit identical plugins. Commit this file.

A lock file entry looks like this:

provider "registry.terraform.io/hashicorp/aws" {
  version     = "5.42.0"
  constraints = "~> 5.40"
  hashes = [
    "h1:abc123...",
    "zh:0a1b2c...",
  ]
}

When to re-run init

You re-run init whenever the things it manages change. The flags below cover the common cases.

FlagUse it when
-upgradeYou want the newest provider/module versions allowed by your constraints, refreshing the lock file
-reconfigureYou changed backend config and want to discard the cached settings, starting fresh
-migrate-stateYou changed backends (e.g. local to S3) and want to copy existing state to the new one
-backend-config=...You supply backend settings from a file or key=value pair at init time
-get=falseYou want to skip module installation

Upgrading providers and modules

The lock file deliberately keeps versions stable. To pick up newer versions within your version constraints, run:

terraform init -upgrade

Output:

Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 5.40"...
- Installing hashicorp/aws v5.49.0...
- Installed hashicorp/aws v5.49.0 (signed by HashiCorp)

Terraform has made some changes to the provider dependency selections recorded
in the .terraform.lock.hcl file. Review those changes and commit them to your
version control system if they represent changes you intended to make.

Reconfiguring or migrating the backend

If you edit the backend block, the next plain init detects the mismatch and stops, asking you to choose. Use -reconfigure to ignore the old cached state association and adopt the new config as-is, or -migrate-state to copy your existing state into the new backend:

# Adopt new backend settings, ignore the cached ones
terraform init -reconfigure

# Move existing state into a newly configured backend
terraform init -migrate-state

Output:

Initializing the backend...
Terraform detected that the backend type changed from "local" to "s3".

Do you want to copy existing state to the new backend?
  Pre-existing state was found while migrating the previous "local" backend
  to the newly configured "s3" backend. Enter "yes" to copy and "no" to
  start with an empty state.

  Enter a value: yes

Successfully configured the backend "s3"!

Always back up your state file before running -migrate-state. State migration is one of the few init operations that can lose data if a credential or network failure interrupts it mid-copy.

Best practices

  • Commit .terraform.lock.hcl and ignore .terraform/ — this is the single most important convention for reproducible builds.
  • Run terraform init early in every CI pipeline before validate and plan; add -input=false so it fails fast instead of hanging on prompts.
  • Use init -upgrade deliberately on its own commit so version bumps are reviewable, never silently mixed with logic changes.
  • Pin provider versions with pessimistic constraints (~> 5.40) rather than leaving them open, so init is predictable.
  • Keep backend settings out of code with -backend-config=prod.tfbackend files when you reuse one configuration across environments.
  • After cloning a repo, run init before anything else — the absence of .terraform/ is expected, not an error.
Last updated June 14, 2026
Was this helpful?