Terraform

Terraform Init – Command Overview with Examples

Terraform init

What is Terraform init?

After writing your Terraform code or cloning your existing Terraform code from source control, the terraform init command is the first step you should take to prepare your working directory. This command initializes the environment by installing the necessary provider plugins and modules and setting up the configuration according to your code. Terraform init enables you to run further commands like terraform plan and terraform apply.

What does the Terraform init command do?

  • Backend initialization
  • Child module installation
  • Plugin installation

Terraform init quick usage examples - command flags

Quick usage examples

terraform init — Initialize the working directory, install required provider plugins and modules, and set up the backend.

terraform init -lock=false — Initialize the working directory; don’t hold a state lock during backend migration.

terraform init -input=false — Initialize the working directory and disable interactive prompts.

terraform init -migrate-state — Reconfigure a backend and attempt to migrate any existing state.

terraform init -upgrade – Ensure you’re using the latest compatible versions of your providers

terraform init -reconfigure – Use the -reconfigure flag to force Terraform to forget any previous configuration and reinitialize.

terraform init -get=false – Disable downloading modules for this configuration

terraform init -plugin-dir=/path/to/custom/plugins – Point Terraform to custom or manually downloaded provider plugins

How to initialize a Terraform file - example configuration files

The example files I will use in this article will create a specified number of groups in Azure AD.

1. Set main.tf file

These files are contained in a directory called az-ad-group. Within it, I have my Terraform configuration files, named main.tf, variables.tf and terraform.tfvars, as well as a .gitignorefile, which will specify which file extensions within the folder the git source control should ignore.

I have a subfolder (or module) within this which holds a main.tf and variables.tf file.

Lastly, the azure-pipeline.yml file specifies the pipeline settings to run terraform init and terraform plan.

AZ-AD-Group
provider "azurerm" {
  features {}
}

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = ">=2.95.0"
    }
    azuread = {
      source  = "hashicorp/azuread"
    }
  }
  backend "azurerm" {
    resource_group_name  = "tf-rg"
    storage_account_name = "jacktfstatesa"
    container_name       = "terraform"
    key                  = "adgroups.tfstate"
  }
}

module "ad_group" {
  source = "./ad_group"
  ad_group_names = var.ad_group_names
}

Note that the main.tf file contains the required_providers and backend blocks. I also call a module called ad_group.

Since this article focuses on the terraform init command, and everything relevant to that command is shown in the above code, I will not publish the rest of the files here, but they can be found in the GitHub repository should you wish to try the example out yourself or delve deeper into the setup.

2. Initialize backend

backend "azurerm" {
    resource_group_name  = "tf-rg"
    storage_account_name = "jacktfstatesa"
    container_name       = "terraform"
    key                  = "adgroups.tfstate"
 }

Before that can happen successfully I will need to login to Azure using the Azure CLI. If I run it without first authenticating, Terraform complains that the resource group containing the storage account cannot be found.

Backend

To login to Azure, use the following commands. The --tenant flag does not need to be specified if you have only one Azure AD tenant linked to your login. If you have multiple tenants linked to your login, you should specify this to avoid confusion.

az login --tenant <tenant ID>
az account set --subscription <subscription ID>
Backend 2
adgroups.tfstate

Any changes to the backend configuration will be detected by Terraform. When terraform init is run, Terraform will throw an error alerting you to the change.

init error
  • migrate-state
  • reconfigure

3. Initialize the Terraform child module

module "ad_group" {
  source = "./ad_group"
  ad_group_names = var.ad_group_names
}

When terraform init is run we can see it being installed:

Initializing modules

4. Initialize the Terraform plugin

Most Terraform providers are published separately from Terraform as plugins. There are hundreds of available providers which allow Terraform to be used with different services. Common providers include azurerm for Microsoft Azure, azuread for Azure Active Directory, and aws for Amazon Web Services. A full list of available providers can be browsed using the Terraform registry.

Init provider plugins

5. Create dependency lock file – terraform.lock.hcl

.terraform.lock.hcl

The contents of the .terraform.lock.hcl file will look like this:

# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.

provider "registry.terraform.io/hashicorp/azuread" {
  version = "2.18.0"
  hashes = [
    "h1:cpppwljjeyqTnwNlQGHK+o1Jb5Tf4UAnJiInNkN6P38=",
    "zh:04b2b5e09dedd45316cd47d21d2ed7e3cd7a4e5f3c8b6e8fba0a10e7eb2a1ca9",
    "zh:232440381b60d918e0da0ea8e8a2e8a78a4fe1ae785b3f829f2f965464ab79a2",
    "zh:688111a9cb8d9ffec2ccabacb27456d275bf1d404dd5f85e681715abbdd64654",
    "zh:7f37b7be7859170f077c58e74be42b5571e364c52aac0a2df3a6a14fbe48d3c5",
    "zh:a385743bfae40f6a01bf6662a3c7a71035113c33965e0dbf421997a015734d08",
    "zh:a97b7430647d7b449441e5515f11a4d123f6d6a383a8fbca5c0a4086be407358",
    "zh:be6d40d1431e8e71a96cce2099a259ef5a8dfb0e849817875d9ee4bb8cf59d40",
    "zh:db3b541d90881d620111fdae0efe90d1e0972fc80a2b4346d4af8d96e1fc1195",
    "zh:e6d9e0481f2bdc16ee69aa00001d9713282daccfbc621e0143c53d9f6dbdb537",
    "zh:ee5b724ca78301057059eff18062fa88d8b24ac7b39f52eb17b8609634427ce0",
    "zh:fdb169f89551f97f6b0bf90d61d5fda166a25cce6867ec16f63c3bfb4d90a0a2",
  ]
}

provider "registry.terraform.io/hashicorp/azurerm" {
  version     = "2.98.0"
  constraints = ">= 2.95.0"
  hashes = [
    "h1:8Sg08lYcJC12Y8EH5oFfgBhIR9OhZFKF633NjOMjilY=",
    "zh:025f656a6d3ecc30f7cc2279bc41969789987b405e3fa8a7c1eb5f74e3ee1140",
    "zh:23c54b330678a16378156193d709bbddce3ba76ee827fd65fb751ce90790af9e",
    "zh:2d28d359ce6881918bd6c03701f6ec4fd90215abfce9b863cfd3172e28c1acb3",
    "zh:31df88584d39cf876fa45ff6de92e67e03814a0985d34c7671bd6989cda22af8",
    "zh:36019109790b9a905770355e5bbb57b291a9689a8b9beac5751dcbdb1282d035",
    "zh:5fb4a277331c459db9e1b150d79b7c7157a176ceca871195e81225e949141b72",
    "zh:7ec304afa1b60dc84257a54cea68e97f85df3feb405d25a9226a4f593ed00744",
    "zh:bac469f104b8ad2c8b5ddc88ddae3b0bc27ae5f9c2ccf03f14a001a5c3ed6ae1",
    "zh:d860b0ec60a978fe3f08d695326e9051a61cd3f60786fc618a61fbdb5d6a4f15",
    "zh:ebcb2911ee27587f63df7eff3836c9a206181a931357c6b9a380124be4241597",
    "zh:f37fae57bf7d05c30fda6e5414ad5a4aad1b34d41a5f2465a864736f92ded1ac",
  ]
}

What is the difference between Terraform init and plan?

Both terraform init and terraform plan are among Terraform’s foundational commands.

The init command prepares the Terraform working directory by installing all the necessary provider plugins, downloading modules, and setting up state storage. In contrast, the plan command generates an execution plan showing infrastructure changes without implementing them.

While init prepares the environment for Terraform, plan previews potential adjustments based on the defined configuration against the current state.

Do you need to run Terraform init before every Terraform plan?

terraform init is the first command you should run in the workflow, however, if you know that no changes have been made to the modules, backend, or provider installations, you can go ahead and run terraform plan without running terraform init first. In automation, it is always best practice to put in a terraform init stage first to make sure the modules, providers, and backend are always up-to-date as specified in your configuration files.

Is it safe to run Terraform init multiple times?

It is always safe to run terraform init. It will never modify the configuration or destroy any resources. If it is run multiple times, it will simply update the working directory with the changes in the configuration. This will be required if the configuration changes include the addition of a new provider block or a change to the backend storage location, for example.

Running Terraform init in automation

terraform init will be the first step in configuring your Terraform workflow in an automation pipeline. In order to set this up in using Azure DevOps pipelines, we will use the azure-pipelines.yml file contained in the example code repository.

stages:
- stage: Build
  displayName: Terraform-Plan  
  jobs:
  - job: TerraformPlan
    displayName: Terraform-Plan
    pool:
      name: Private-Build-Agents
    steps:
    - checkout: self
    - script: ls $(System.DefaultWorkingDirectory)
    - task: TerraformInstaller@0
      displayName: 'Use Terraform latest'

    - task: TerraformCLI@0
      displayName: Terraform-Init
      inputs:
        command: 'init'
        workingDirectory: '$(System.DefaultWorkingDirectory)'
        backendType: 'azurerm'
        backendServiceArm: 'IAC Service Connection-Azure'
        backendAzureRmResourceGroupName: 'tf-rg'
        backendAzureRmStorageAccountName: 'jacktfstatesa'
        backendAzureRmContainerName: 'terraform'
        backendAzureRmKey: 'adgroups.tfstate'

    - task: TerraformCLI@0
      displayName: Terraform-Plan
      inputs:
        command: 'plan'
        workingDirectory: '$(System.DefaultWorkingDirectory)'
        environmentServiceName: 'RG Service Connection'
Downloading task
Terraform-Init

In some cases where you have lots of providers specified and want to avoid them being installed repeatedly on each pipeline run by terraform init, you may wish to make the providers available locally. This is possible and is covered in this advanced ‘Terraform in automation’ tutorial.

Terraform init options

  • backend=false
  • backend-config=path
  • force-copy
  • from-module=SOURCE
  • get=false
  • input=false
  • lock=false
state blob is already locked
Break lease
az storage blob lease break -b terraform.tfstate -c myAzureStorageAccountContainerName --account-name "myAzureStorageAccountName" --account-key "myAzureStorageAccountAccessKey"

Or using Terraform you can force the unlock, (get the LockID from the error) e.g.

terraform force-unlock <LockId>
  • lock-timeout=<duration>
  • no-color
color
no-color
  • plugin-dir
  • upgrade
azuread = {
   source  = "hashicorp/azuread"
   version = "=2.17.0"
}

If I then proceed to remove the version constraint from the azuread provider:

azuread = {
   source  = "hashicorp/azuread"
}
init upgrade

When re-run with the upgrade flag, you will notice that Terraform searches for the latest version of the azuread provider (v2.18.0 at the time of writing). Also, notice that any modules in the configuration are also upgraded.

init upgrade 2
  • migrate-state
  • reconfigure
  • lockfile=MODE
  • ignore-remote-version

Terraform init errors and troubleshooting

In the table below are the common terraform init errors and their solutions.

Error Troubleshooting
Provider/Modules Plugins Not Found / Download failures Ensure the required providers are correctly specified in your configuration

– If you are using a private network ensure a proxy is in place

– If you are using a private registry, ensure you have logged in successfully to it, or if it has the required provider

Unsupported Terraform Version – Review the “required_version” setting in your Terraform configuration

– Upgrade or downgrade your Terraform binary to a supported version 

Backend Initialization failure Ensure the backend configuration details are correct
– Check permissions and authentication
State Locking Errors Ensure the DynamoDB table is correctly set up if you are using it for locking
– Manually solve dangling locks
Initialization conflicts – A previous “.terraform” directory may cause conflicts – deleting it and rerunning init may fix the issue

Key Points

The terraform init command is the first command you should use to prepare the working directory. terraform init specifically performs the following actions:

  • Backend Initialization
  • Child Module Installation
  • Plugin Installation

Note: New versions of Terraform will be placed under the BUSL license, but everything created before version 1.5.x stays open-source. OpenTofu is an open-source version of Terraform that will expand on Terraform’s existing concepts and offerings. It is a viable alternative to HashiCorp’s Terraform, being forked from Terraform version 1.5.6. OpenTofu retained all the features and functionalities that had made Terraform popular among developers while also introducing improvements and enhancements. OpenTofu works with your existing Terraform state file, so you won’t have any issues when you are migrating to it. 

Don’t forget to take a look at how Spacelift helps you manage the complexities and compliance challenges of using Terraform. It brings with it a GitOps flow, so your infrastructure repository is synced with your Terraform Stacks, and pull requests show you a preview of what they’re planning to change. It also has an extensive selection of policies, which lets you automate compliance checks and build complex multi-stack workflows. You may also check how initialization policies work with Spacelift.

Terraform Management Made Easy

Spacelift effectively manages Terraform state, more complex workflows, supports policy as code, programmatic configuration, context sharing, drift detection, resource visualization and includes many more features.

Start free trial
Terraform CLI Commands Cheatsheet

Initialize/ plan/ apply your IaC, manage modules, state, and more.

Share your data and download the cheatsheet