terraform init

By Vishvesh Patel · DevOps EngineerUpdated July 12, 2026

Learn exactly what terraform init does, downloading providers, setting up backends, creating the lock file, and how to use init flags like -upgrade and -reconfigure.

What Is terraform init?

terraform init is the very first command you run in any Terraform project. It prepares your working directory so that every other Terraform command (plan, apply, destroy) can work correctly.

Think of it like npm install or pip install, it sets up the dependencies your project needs before you can do anything else.

terraform init

What terraform init Does Internally

When you run terraform init, Terraform does three things:

1. Downloads Provider Plugins

Terraform reads the required_providers block in your configuration and downloads the declared providers from the Terraform Registry (or a private registry):

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
    random = {
      source  = "hashicorp/random"
      version = "3.6.0"
    }
  }
}

Running init on this configuration downloads both the AWS and Random providers into .terraform/providers/. This directory can be hundreds of megabytes, always add it to .gitignore.

Sample output:

Initializing the backend...

Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 5.0"...
- Finding hashicorp/random versions matching "3.6.0"...
- Installing hashicorp/aws v5.54.1...
- Installing hashicorp/random v3.6.0...

Terraform has been successfully initialized!

2. Sets Up the Backend

If you have a backend block configured, init connects to it and migrates state if needed:

terraform {
  backend "s3" {
    bucket = "my-tfstate-bucket"
    key    = "production/terraform.tfstate"
    region = "us-east-1"
  }
}

When switching from local state to a remote backend, init asks:

Do you want to copy existing state to the new backend?
  yes/no:

3. Creates the Lock File

terraform init writes .terraform.lock.hcl, a file that pins the exact provider versions downloaded:

# .terraform.lock.hcl (auto-generated)
provider "registry.terraform.io/hashicorp/aws" {
  version     = "5.54.1"
  constraints = "~> 5.0"
  hashes = [
    "h1:abc123...",
  ]
}

Always commit .terraform.lock.hcl to Git. It ensures every team member and every CI/CD pipeline uses exactly the same provider versions, preventing "works on my machine" failures caused by version drift.

The .terraform Directory

After init, your project will have:

my-project/
├── main.tf
├── variables.tf
├── .terraform/                    # ← created by init, add to .gitignore
│   ├── providers/
│   │   └── registry.terraform.io/
│   │       └── hashicorp/
│   │           └── aws/5.54.1/    # downloaded provider binary
│   └── terraform.tfstate          # backend config cache
└── .terraform.lock.hcl            # ← commit this to Git

Common init Flags

-upgrade

Re-download all providers, selecting the newest version that satisfies your constraints:

terraform init -upgrade

Use this when you want to update providers to the latest allowed version. Without -upgrade, init uses the versions already in the lock file.

Warning: Always run terraform plan after -upgrade to check for breaking changes in the new provider version.

-reconfigure

Force init to reconfigure the backend without migrating state:

terraform init -reconfigure

Useful when you have changed your backend configuration and want to switch without copying existing state.

-backend=false

Skip backend initialisation entirely:

terraform init -backend=false

Useful in CI pipelines where you only want to validate the configuration without connecting to a remote backend.

-backend-config

Pass backend configuration values at init time instead of hardcoding them in the backend block, great for keeping bucket names or credentials out of source code:

terraform init \
  -backend-config="bucket=my-tfstate-bucket" \
  -backend-config="key=production/terraform.tfstate" \
  -backend-config="region=us-east-1"

When to Re-run init

You must re-run terraform init whenever you:

ChangeWhy
Add or remove a required_providers entryNew provider needs to be downloaded
Change provider version constraintsDifferent version needs to be installed
Change the backend blockBackend connection must be re-established
Clone a repo for the first timeProviders are not committed to Git
Add or update a module sourceModule code needs to be downloaded

It is always safe to re-run init, it never modifies your infrastructure.

init in CI/CD Pipelines

In a CI/CD pipeline, always run init before plan or apply. Use the -input=false flag to prevent interactive prompts:

# GitLab CI example
terraform-plan:
  script:
    - terraform init -input=false
    - terraform plan -out=tfplan

Knowledge Check

Exercise

Question 1: Lock File Purpose

After running terraform init, you see a .terraform.lock.hcl file. A teammate asks if they should commit it. What do you tell them?

Exercise

Question 2: When to Re-run init

You add a new provider to required_providers in your main.tf. You run terraform plan immediately. What happens?

Exercise

Question 3: terraform init -upgrade

Your lock file pins AWS provider at v5.0.0. A new version v5.54.1 is available. You want to update. What command do you run?


Frequently Asked Questions

What does terraform init actually do?

Four things. It downloads the provider plugins your configuration requires into .terraform/, fetches any external modules, configures the backend where state will be stored, and writes or verifies .terraform.lock.hcl with the exact provider versions and checksums. Until it has run, no other Terraform command works, because Terraform has no providers loaded and does not know where state lives.

When do I need to re-run terraform init?

Whenever the things it sets up change: after adding or changing a provider or its version constraint, after adding or updating a module source, after changing the backend configuration, and after cloning a repository for the first time since .terraform/ is not committed. Terraform tells you when it is needed with an error saying the configuration has changed since initialisation. Running it again when it is not needed is harmless.

What is the difference between terraform init and terraform init -upgrade?

Plain init respects .terraform.lock.hcl and installs exactly the provider versions recorded there, which is what makes builds reproducible. -upgrade ignores the locked versions, resolves the newest releases allowed by your version constraints, and rewrites the lock file. Use -upgrade deliberately when you intend to move provider versions, then review the lock file diff like any other dependency bump, never as a reflex when something is failing.

Should I commit the .terraform directory?

No. It contains downloaded provider binaries which are large, platform-specific and reproducible from the lock file, so committing them bloats the repository for no benefit. Add .terraform/ to .gitignore. Do commit .terraform.lock.hcl though, that is the small text file recording which versions to install, and it is what makes everyone's init produce the same result.

How do I run terraform init in CI?

Run it at the start of every job, since CI workspaces start empty. Use -input=false so it never waits for interactive input, and -backend-config to supply backend settings from environment variables or secrets rather than committing them. Caching the .terraform directory between runs speeds things up noticeably on large provider sets, but key the cache on the lock file so a provider change invalidates it.

Why does init fail with a provider registry error?

Usually network access or a version constraint that cannot be satisfied. In a restricted network the registry may be unreachable, in which case a provider mirror or a network policy change is needed. If the error names a version, your constraints conflict. Perhaps a module requires a provider version your root configuration excludes. Read the constraint chain in the error, which names each source, and reconcile them in required_providers.

Continue Learning

Explore Related Topics

Try the Tool

Practise this in the browser

Terraform Playground

Run init, plan, apply and destroy against simulated infrastructure.

When it breaks

Related Resources