Terraform Init – Command Overview
Tags: terraform, infrastructureascode, devops
Published: 2024-06-04 06:40:19

In this post, we will explain what the `terraform init` command is used for, what it does, and when to run it. We will explore the options available and give an example of when to use it in automation using Azure DevOps.

##What is Terraform init?

After writing your [Terraform](https://spacelift.io/blog/what-is-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?

In order to prepare the working directory for use with Terraform, the `terraform init` command performs the following steps:

-   Backend initialization

-   Child module installation

-   Plugin installation

We will look at each of these in more detail in this article.

##Quick usage examples: Terraform init command flags
If you are looking for some quick examples on how to use the `terraform init` command, some of the more common usage flags are listed below. Later in the article, we will deep dive into some of these and provide examples.

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](https://spacelift.io/blog/terraform-migrate-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

`terraform init -input` - Provide values for required input variables during initialization

##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](https://spacelift.io/blog/terraform-active-directory).

### 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 `.gitignore`file, 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`](https://spacelift.io/blog/terraform-plan).

![AZ-AD-Group](https://spacelift.io/_next/image?url=https%3A%2F%2Fspaceliftio.wpcomstaging.com%2Fwp-content%2Fuploads%2F2022%2F03%2Finit1.png&w=3840&q=75)

```

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](https://github.com/spacelift-io-blog-posts/Blog-Technical-Content/tree/master/az-ad-group-module) should you wish to try the example out yourself or delve deeper into the setup.

### 2\. Initialize backend

My `main.tf` file is configured to use a storage account I have set up in Azure to store the Terraform state file. This is known as the 'backend'.

When `terraform init` runs, it will first attempt to initialize the 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](https://spacelift.io/_next/image?url=https%3A%2F%2Fspaceliftio.wpcomstaging.com%2Fwp-content%2Fuploads%2F2022%2F03%2Finit2.png&w=3840&q=75)

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>

```

Once authenticated successfully, run the `terraform init` command again:

![Backend 2](https://spacelift.io/_next/image?url=https%3A%2F%2Fspaceliftio.wpcomstaging.com%2Fwp-content%2Fuploads%2F2022%2F03%2Finit3.png&w=3840&q=75)

This time we see the backend was initialized successfully.

In the storage account in Azure, in my terraform container, I can see that the `adgroups.tfstate` file has been created successfully.

![adgroups.tfstate](https://spacelift.io/_next/image?url=https%3A%2F%2Fspaceliftio.wpcomstaging.com%2Fwp-content%2Fuploads%2F2022%2F03%2Finit4.png&w=3840&q=75)

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](https://spacelift.io/_next/image?url=https%3A%2F%2Fspaceliftio.wpcomstaging.com%2Fwp-content%2Fuploads%2F2022%2F03%2Finit5.png&w=3840&q=75)

In this scenario, there are two options:

-   `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.

💡 You might also like:

-   [The Impact of Terraform License Change](https://spacelift.io/blog/terraform-license-change)

-   [What is Terraform Map Variable?](https://spacelift.io/blog/terraform-map-variable)

-   [24 Most Useful Terraform Tools](https://spacelift.io/blog/terraform-tools)

### 3\. Initialize the Terraform child module

A [*Terraform module*](https://spacelift.io/blog/what-are-terraform-modules-and-how-do-they-work) is a container for multiple resources that are used together.

In my example code, my `main.tf` calls my child module `ad_group`.

```

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](https://spacelift.io/_next/image?url=https%3A%2F%2Fspaceliftio.wpcomstaging.com%2Fwp-content%2Fuploads%2F2022%2F03%2Finit6.png&w=3840&q=75)

If you have any `module` blocks defined in your configuration files, these will be installed when executing the init command. The location of the source code for the referenced modules is defined in the `source` argument of the module block. All modules require a `source` argument.

The `source` of a module block can point to a local module, or a remote source such as a module held in a central repository, GitHub, Bitbucket, or a module in the public terraform registry. If the code is remote, it will be downloaded from the source specified to a local directory so it can be used by other [Terraform commands](https://spacelift.io/blog/terraform-commands-cheat-sheet).

After adding, removing, or modifying module blocks, `terraform init` must be run again in order for Terraform to make the necessary adjustments that have been defined in the configuration.

Re-running the `terraform init` command will not amend any modules that have already been installed if the configuration of those modules has not been changed. It will, however, install any modules added since the last time `terraform init` was executed. To force all modules to be re-installed, the `-upgrade` flag can be specified.

Child module installation can also be skipped by using the `-get=false` flag, this should only be used if the child modules have already been installed and no additions, deletions, or changes to the modules have been made. Note that Terraform builds an internal 'module tree' when `terraform init` is run, and if this is not complete, then other steps performed by `terraform init` will not complete successfully. It is, for this reason, the `-get=false` flag should be used with caution.

### 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](https://registry.terraform.io/browse/providers).

During `terraform init` the registry is searched for those providers that are specified directly in the configuration files but also searches for providers that are not specified directly (indirect). They will be automatically found, downloaded, and installed if they are present in the registry.

As well as searching the public [Terraform registry](https://spacelift.io/blog/terraform-registry) for providers, it is also possible to use a third-party registry, by specifying the `-plugin-dir=PATH` flag.

If you do not wish to use these options, a `provider_installation` block can be configured in your code to override Terraforms default provider installation behavior, allowing the use of a local mirror for some or all of your required providers.

When I run `terraform init` with my example code, I see the following output:

![Init provider plugins](https://spacelift.io/_next/image?url=https%3A%2F%2Fspaceliftio.wpcomstaging.com%2Fwp-content%2Fuploads%2F2022%2F03%2Finit7.png&w=3840&q=75)

Terraform searches the registry for the required `azuread` and `azurerm` providers and installs the appropriate versions as specified in my configuration files.

If I do not specify the version for a particular provider, Terraform will look for the latest version. It is recommended to always *pin *the provider version as upgrades may cause unexpected behavior over time. For example, the `azuread` v2.18.0 provider will have introduced many changes compared to v2.17.0.

Refer to the `main.tf` file at the beginning of the article for an example of this at line 9, which pins the version of the `azurerm` provider.

### 5\. Create dependency lock file - terraform.lock.hcl

Once providers have been successfully installed, Terraform creates a dependency lock file and writes information about the providers to it. This file will be named `.terraform.lock.hcl` and should ideally be committed to your repository in your version control system to ensure that the same provider versions are used when `terraform init` is run again in the future.

Using my example configuration code, once `terraform init` has been run, Terraform will advise that the `.terraform.lock.hcl` file has been created.

![.terraform.lock.hcl](https://spacelift.io/_next/image?url=https%3A%2F%2Fspaceliftio.wpcomstaging.com%2Fwp-content%2Fuploads%2F2022%2F03%2Finit8.png&w=3840&q=75)

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",

  ]

}

```

Notice that the versions are specified, as well as any version constraints. In my `main.tf` file I specified a constraint for the `azurerm` provider, but not my `azuread` provider.

If you want to force Terraform to look for newer versions than those contained in the lock file, you can specify the `--upgrade` option, an example of which can be found in the 'terraform init options' section of this article.

##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](https://spacelift.io/blog/what-is-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'

```

This file specifies the pipeline in YAML format. As the pipeline is defined as code rather than set up manually through the Azure DevOps GUI, it can be considered 'pipeline-as-code', whereas terraform configuration files themselves would be considered 'infrastructure-as-code'.

The pipeline file specifies two stages, the `terraform init` stage and a `terraform plan` stage.

The `terraform init` stage is specified starting at line 15. Note the backend details are specified here. They can also be specified in the `main.tf` configuration file, but if they were committed from the file, the pipeline would still run using the values specified in the `azure-pipelines.yml` file.

During the pipeline run, Azure DevOps will run the Terraform CLI task with the Azure DevOps plugin which it will set up during the 'initialize job' phase.

![Downloading task](https://spacelift.io/_next/image?url=https%3A%2F%2Fspaceliftio.wpcomstaging.com%2Fwp-content%2Fuploads%2F2022%2F03%2Finit9.png&w=3840&q=75)

![Terraform-Init](https://spacelift.io/_next/image?url=https%3A%2F%2Fspaceliftio.wpcomstaging.com%2Fwp-content%2Fuploads%2F2022%2F03%2Finit10.png&w=3840&q=75)

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'](https://learn.hashicorp.com/tutorials/terraform/automate-terraform?in=terraform/automation&utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial.

##Terraform init options

There are multiple options that can be used with the `terraform init` command that can be viewed using the `--help` flag. Below are some examples of the more useful and commonly used 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](https://spacelift.io/_next/image?url=https%3A%2F%2Fspaceliftio.wpcomstaging.com%2Fwp-content%2Fuploads%2F2022%2F03%2Finit11.png&w=3840&q=75)

Error message: State blob is already locked

The easiest fix for this issue is to navigate to the storage account and then to the container in the Azure portal that holds the state file. The blob will show as 'Leased' under the leased state column. Select the state file and hit the 'break lease' button.

![Break lease](https://spacelift.io/_next/image?url=https%3A%2F%2Fspaceliftio.wpcomstaging.com%2Fwp-content%2Fuploads%2F2022%2F03%2Finit12.png&w=3840&q=75)

Lease state on the state file blob should then show as 'broken', and you can kick off the next Terraform run.

You can also use Azure CLI to do this, e.g.

```

az storage blob lease break -b terraform.tfstate -c myAzureStorageAccountContainerName --account-name "myAzureStorageAccountName" --account-key "myAzureStorageAccountAccessKey"

```

Or, using [Terraform you can force the unlock](https://spacelift.io/blog/terraform-force-unlock), (get the LockID from the error) e.g.

```

terraform force-unlock <LockId>

```

You can also specify the `lock=false` option which as mentioned might be dangerous if others might be concurrently running against the same state file, so it is better to fix the issue using the steps above.

### 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.

For example, when [using Terraform in an Azure DevOps release pipeline](https://spacelift.io/blog/terraform-azure-devops), you may notice that the encoding on the console output has annoying characters displayed. This is caused by Terraform attempting to output colors to the console to signify additions, deleting, changes, etc. Azure DevOps can't handle this. Examples are as follows:

![color](https://spacelift.io/_next/image?url=https%3A%2F%2Fspaceliftio.wpcomstaging.com%2Fwp-content%2Fuploads%2F2022%2F03%2Finit13.png&w=3840&q=75)

![no-color](https://spacelift.io/_next/image?url=https%3A%2F%2Fspaceliftio.wpcomstaging.com%2Fwp-content%2Fuploads%2F2022%2F03%2Finit14.png&w=3840&q=75)

### 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*.*

You can use pre-installed plugins by either putting them in the same directory as the Terraform binary or by setting the `-plugin-dir` flag. This might be desirable when you have connectivity issues or restrictions to [https://releases.hashicorp.com](https://releases.hashicorp.com/).

### 11\. `terraform init -upgrade`

`terraform init -upgrade` is useful when any pinned provider versions have been changed and you want to force Terraform to search for the latest version.

For example, if I pin my provider version for `azuread` to version 2.17.0, on running `terraform init` for the first time, this is the version that will be installed.

```

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"

}

```

Then re-run `terraform init` you will notice that Terraform reports that it will use the previously installed version (still version 2.17.0) rather than searching again for the latest version.

![init upgrade](https://spacelift.io/_next/image?url=https%3A%2F%2Fspaceliftio.wpcomstaging.com%2Fwp-content%2Fuploads%2F2022%2F03%2Finit15.png&w=3840&q=75)

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](https://spacelift.io/_next/image?url=https%3A%2F%2Fspaceliftio.wpcomstaging.com%2Fwp-content%2Fuploads%2F2022%2F03%2Finit16.png&w=3840&q=75)

### 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.

##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

It is always safe to run `terraform init`. It can be used in automation and comes with a myriad of options that can be used to further control its behavior.

**Note**: New versions of Terraform will be placed under the BUSL license, but everything created before version 1.5.x stays open-source. [OpenTofu](https://opentofu.org/) 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.

Don't forget to take a look at how [Spacelift helps you manage the complexities and compliance challenges of using Terraform](https://docs.spacelift.io/vendors/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](https://docs.spacelift.io/concepts/policy/run-initialization-policy).

_Written by Jack Roper and Flavius Dinu._