Going to AWS re:Invent 2024?

➡️ Book a meeting with Spacelift

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.

Terraform init is a CLI command that initializes the Terraform 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.

How does Terraform init work?

  • Backend initialization
  • Child module installation
  • Plugin installation

Quick usage examples: Terraform init 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 Terraform 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 we 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
  • terraform init -migrate-state To reconfigure the backend and attempt to migrate any existing state.
  • terraform init -reconfigure To reconfigure a backend while ignoring any saved configuration.

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. To set this up 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

1. terraform init -backend=false

Terraform init backend=false lets you disable backend or Terraform Cloud initialization for this configuration and use what what was previously initialized instead. aliases: -cloud=false.

As you might infer, this option does not create a local backend

2. terraform init -backend-config=path

When you use terraform init -backend-config=path, your configuration will be merged with that in the configuration file’s ‘backend’ block. This option allows you to dynamically configure the backend by passing in a file path or key/value pairs during the initialization process, separating potentially sensitive values from your main Terraform code.

3. terraform init -force-copy

terraform init -force-copy is used to suppress prompts about copying state data when initializing a new state backend. It allows you to initialize a new backend and migrate the state data from the previous backend automatically, without any interactive prompts for confirmation. This enables smoother backend switching in automated workflows. However, it can potentially cause data loss if the state is being copied incorrectly.

4. terraform init -from-module=SOURCE

With terraform -init from-module=SOURCE you can initialize the current working directory with the contents of the specified module source.

5. terraform init -get=false

terraform init -get=false initialize a Terraform working directory by installing providers but skipping automatically downloading any declared modules. This can be useful in certain workflows where you want more control over when modules are downloaded or updated

If the working directory has been previously initialized without any further changes, this can be used to prevent child modules from being re-downloaded.

6. terraform init -input=false

terraform init -input=false command is used to initialize the Terraform working directory without prompting for any input.

This is useful in automation pipelines where the run may simply hang and time out waiting for input. For example, if your code had an error that prompted for a value for a missing variable, the pipeline would prompt for this rather than erroring and finishing the run.

7. terraform init -lock=false

terraform init -lock=false disables the locking of the state file during the initialization step. When Terraform runs, it locks the state file so it cannot be modified by other processes.

If a Terraform run ends unexpectedly (crashes or is canceled mid-run), or multiple pipelines have been running simultaneously using the same state file, then the state file remains locked. On the next run, you may see any error as pictured below, showing that the ‘state blob is already locked’.

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>

8. terraform init -lock-timeout=<duration>

With terraform init -lock-timeout=<duration> you can specify the maximum time Terraform should wait to acquire a lock on the state file during initialization.

9. terraform init -no-color

terraform init -no-color initializes the Terraform working directory as usual, but with all color codes removed from the command output.

color
no-color

10. terraform init -plugin-dir

You can use terraform init with the -plugin-dir option to specify an alternate directory for Terraform to install and look for provider plugins.

11. terraform init -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-runnig 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). Notice that any modules in the configuration have also been upgraded.

init upgrade 2

12. terraform init -migrate-state

terraform init -migrate-state lets you migrate your Terraform state data from one backend to another when changing backend configurations

13. terraform init -reconfigure

terraform init -reconfigure option is used to reconfigure the backend for an existing Terraform working directory while ignoring any previously saved configuration.

14. terraform init -ignore-remote-version

terraform init -ignore-remote-version command is a rarely used option that lets you override checking that the local and remote Terraform versions agree when using the remote backend, allowing an operation to proceed even when there is a version mismatch.

Terraform init errors and troubleshooting

The table below shows 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

Terraform init best practices

Here are some best practices to keep in mind when running terraform init:

  1. Make sure all required modules are available and versioned correctly in your Terraform configurations before running terraform init, as this command will automatically download and install any necessary Terraform modules and providers.
  2. Utilize provider locking to ensure that Terraform uses specific versions of providers to avoid unexpected changes due to provider updates.
  3. Re-run terraform init to reinitialize settings after any significant changes to configurations or updates to Terraform itself.
  4. Automate the execution of terraform init as part of your continuous integration (CI) pipeline to ensure that any changes in Terraform code are validated and that the initialization step is consistent across different environments.

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

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.

Note: New versions of Terraform are 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 expands on Terraform’s existing concepts and offerings. It is a viable alternative to HashiCorp’s Terraform, being forked from Terraform version 1.5.6.

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

The Practitioner’s Guide to Scaling Infrastructure as Code

Transform your IaC management to scale

securely, efficiently, and productively

into the future.

ebook global banner
Share your data and download the guide