Initialize Terraform configuration
The core Terraform workflow consists of three main steps after you have written your Terraform configuration:
- Initialize prepares your workspace so Terraform can apply your configuration.
- Plan allows you to preview the changes Terraform will make before you apply them.
- Apply makes the changes defined by your plan to create, update, or destroy resources.
When you initialize a Terraform workspace, Terraform configures the backend,
installs all providers and modules referred to in your configuration, and
creates a version lock file if one doesn't already exist. In addition, you can
use the terraform init
command to change your workspace's backend and upgrade
your workspace's providers and modules.
In this tutorial, you will initialize a Terraform workspace that uses both local
and remote modules, explore the .terraform
directory that Terraform uses to
store your providers and modules, and update your provider and module versions.
In the process, you will learn more about the terraform init
command's
integral role in the Terraform workflow.
Prerequisites
You can complete this tutorial using the same workflow with either Terraform Community Edition or HCP Terraform. HCP Terraform is a platform that you can use to manage and execute your Terraform projects. It includes features like remote state and execution, structured plan output, workspace resource summaries, and more.
Select the HCP Terraform tab to complete this tutorial using HCP Terraform.
This tutorial assumes that you are familiar with the Terraform workflow. If you are new to Terraform, complete the Get Started tutorials first.
In order to complete this tutorial, you will need the following:
- Terraform v1.6+ installed locally.
Clone the example repository
In your terminal, clone the learn-terraform-init
repository.
$ git clone https://github.com/hashicorp-education/learn-terraform-init
Navigate to the cloned repository.
$ cd learn-terraform-init
Review configuration
This directory contains Terraform configuration that uses multiple providers, a local module, and a remote module. You will use these resources to review how Terraform initializes the working directory.
$ tree.├── LICENSE├── README.md├── main.tf├── modules│ └── aws-ec2-instance│ ├── main.tf│ └── variables.tf├── terraform.tf└── variables.tf
The example repository includes the following:
LICENSE
includes the text of the Mozilla Public License under which HashiCorp distributes the example configuration.README.md
describes the example configuration.main.tf
includes the resources and data sources used by the example configuration.the
modules/aws-ec2-instance
directory includes a Terraform module to provision an EC2 instance on AWS.terraform.tf
defines theterraform
block, which defines the providers, remote backend, and the Terraform version(s) to be used with this configuration.variables.tf
defines the variables used in this configuration.
Initialize your workspace
Initialize your Terraform workspace.
$ terraform init
The output describes the steps Terraform executes when you initialize your workspace.
First, Terraform initializes the backend.
Since the terraform
block does not include a
cloud
or
backend
block,
Terraform defaults to the local
backend.
Initializing the backend...
Next, Terraform downloads the modules required by your configuration.
Terraform recognizes that the module "ec2-instance"
block uses the local
modules/aws-ec2-instance
module. Next, Terraform determines that the module
"hello"
block references a remote module, so it downloads it from the public
Terraform Registry.
Initializing modules...- ec2-instance in modules/aws-ec2-instanceDownloading registry.terraform.io/joatmon08/hello/random 4.0.0 for hello...- hello in .terraform/modules/hello
Note
When you change a module's source or version, you must either re-initialize
your Terraform configuration or run terraform get
to download the new module.
Next, Terraform downloads the providers required by your configuration.
Since the configuration does not yet have a lock file, Terraform downloaded the
aws
and random
providers specified in the required_providers
block found
in terraform.tf
.
Initializing provider plugins...- Finding hashicorp/aws versions matching "5.43.0"...- Finding hashicorp/random versions matching "3.6.0"...- Installing hashicorp/aws v5.43.0...- Installed hashicorp/aws v5.43.0 (signed by HashiCorp)- Installing hashicorp/random v3.6.0...- Installed hashicorp/random v3.6.0 (signed by HashiCorp)
When you initialize a workspace, Terraform will attempt to download the provider
versions specified by the workspace's lock file. If the lock file does not
exist, Terraform will use the required_providers
block to determine the
provider version and create a new lock file. If neither exists, Terraform will
search for a matching provider and download the latest version.
Next, Terraform creates the lock file if it does not already exist, or updates it if necessary.
Terraform's lock file, .terraform.lock.hcl
, records the versions and hashes of
the providers used in this run. This ensures consistent Terraform runs in
different environments, since Terraform will download the versions recorded in
the lock file for future runs by default.
Terraform has created a lock file .terraform.lock.hcl to record the providerselections it made above. Include this file in your version control repositoryso that Terraform can guarantee to make the same selections by default whenyou run "terraform init" in the future.
When you manage Terraform configuration in a source control repository,
commit the .terraform.lock.hcl
file along with your configuration files.
Finally, Terraform prints out a success message and reminds you how to plan your
configuration, and to re-run terraform init
if you change your modules or
backend configuration.
Terraform has been successfully initialized!You may now begin working with Terraform. Try running "terraform plan" to seeany changes that are required for your infrastructure. All Terraform commandsshould now work.If you ever set or change modules or backend configuration for Terraform,rerun this command to reinitialize your working directory. If you forget, othercommands will detect it and remind you to do so if necessary.
Validate your configuration
Now that you have initialized your workspace and downloaded the required modules and providers, Terraform can verify whether your configuration syntax is valid and internally consistent. This includes checking if your resources blocks have invalid or missing arguments. You must initialize your workspace before you can validate your configuration.
Validate your configuration.
$ terraform validateSuccess! The configuration is valid.
Review initialization artifacts
When you initialize a new Terraform workspace, it creates a lock file
named .terraform.lock.hcl
and the .terraform
directory.
Explore the lock file
The lock file ensures that Terraform uses the same provider versions across your team and in remote execution environments. During initialization, Terraform will download the provider versions specified by this file rather than the latest versions.
Open .terraform.lock.hcl
to review its structure and contents.
.terraform.lock.hcl
# This file is maintained automatically by "terraform init".# Manual edits may be lost in future updates. provider "registry.terraform.io/hashicorp/aws" { version = "5.43.0" constraints = "5.43.0" hashes = [ "h1:3w6NCYy+mbc9odXmM7K5Xag2ggtapraacZqJR3WpJKc=", "zh:07fb2abb9cf4d2042b41b2b2c642d4c4bd2feccbd856cd7040a7d15158fed478", "zh:1373339e796d8d8473c267c0ecddb701559fce454c2cdd192cf8b0eadf759b48", "zh:1644b4e0fd2e0b28d465bb5cf08b1f594a623324d176e879e5052f78cd2ea8cb", "zh:385943b8d4170c5269b8e13e876636b7edc0ad2576edc7eb5d81cd4286a461d8", "zh:48cf103f4fa866b67b686e8c085ac15264d6f020b6ad4a90f496b7283d31faa6", "zh:4a4c4b4236542089d1bdb688c248e0b7c941ce42887da87e487bfb15038dcaf9", "zh:5d84f3e12100bdd62a8c295b56358b82afc130642dca80d104bd868fdc28ed7c", "zh:68294a601ce588a8838bcf4e136bb5ed8d2b1ee410f8871d88e35ce4861cf33f", "zh:7ae1af6e9b95bd6c33dd0922216ac2b59f2f5b22fedbeab1db7a80b2f4358919", "zh:89c718d41b2eeeaefd1acdbd839f1326a8c866bd49752648b0b32d3dd4a38163", "zh:96e54ccb0f5ddf60465edf5c9f46e64f7d2f392507b851f102723797b4a15d09", "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", "zh:b102ce204ebbbf32d68ff47b5224eeb60873bef5b58a7fd7790f6b4020801578", "zh:cae4cb16d15ac4b15c8de5bc9dddc2032583e12c4f31e23b3a7ef22da60657dc", "zh:fecbcbd63111c9518de261bcb37482cb06ee149e7298f567d45b2a55674faa75", ]} provider "registry.terraform.io/hashicorp/random" { version = "3.6.0" constraints = "3.6.0" hashes = [ "h1:I8MBeauYA8J8yheLJ8oSMWqB0kovn16dF/wKZ1QTdkk=", "zh:03360ed3ecd31e8c5dac9c95fe0858be50f3e9a0d0c654b5e504109c2159287d", "zh:1c67ac51254ba2a2bb53a25e8ae7e4d076103483f55f39b426ec55e47d1fe211", "zh:24a17bba7f6d679538ff51b3a2f378cedadede97af8a1db7dad4fd8d6d50f829", "zh:30ffb297ffd1633175d6545d37c2217e2cef9545a6e03946e514c59c0859b77d", "zh:454ce4b3dbc73e6775f2f6605d45cee6e16c3872a2e66a2c97993d6e5cbd7055", "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", "zh:91df0a9fab329aff2ff4cf26797592eb7a3a90b4a0c04d64ce186654e0cc6e17", "zh:aa57384b85622a9f7bfb5d4512ca88e61f22a9cea9f30febaa4c98c68ff0dc21", "zh:c4a3e329ba786ffb6f2b694e1fd41d413a7010f3a53c20b432325a94fa71e839", "zh:e2699bc9116447f96c53d55f2a00570f982e6f9935038c3810603572693712d0", "zh:e747c0fd5d7684e5bfad8aa0ca441903f15ae7a98a737ff6aca24ba223207e2c", "zh:f1ca75f417ce490368f047b63ec09fd003711ae48487fba90b4aba2ccf71920e", ]}
If the versions defined in the lock file's provider
block do not match the
versions defined in your configuration's required_providers
block, Terraform
will prompt you to re-initialize your configuration using the -upgrade
flag.
You will do this in the next section.
Explore the .terraform
directory
Terraform uses the .terraform
directory to store the project's providers and
modules. Terraform will refer to these components when you run validate
,
plan
, and apply
,
Note
Terraform automatically manages the .terraform
directory. Do not check it
into version control, and do not directly modify this directory's contents.
Exploring the .terraform
directory in this tutorial is meant to deepen your
understanding of how Terraform works, but the contents and structure of this
directory are subject to change between Terraform versions.
View the .terraform
directory structure.
$ tree .terraform -L 1.terraform├── modules└── providers
Notice that the .terraform
directory contains two sub-directories: modules
and providers
. These two directories contain the modules and providers used by
your Terraform workspace.
The
.terraform/modules
directory contains amodules.json
file, and a local copy of the remote module, "hello".$ tree .terraform/modules├── hello│ ├── README.md│ └── random.tf└── modules.json
Open
modules.json
. This file shows that the configuration uses three modules: the "root" module, referring to the configuration in the root directory of your workspace, the localaws-ec2-instance
module, and the remotehello
module.modules.json
{ "Modules": [ { "Key": "", "Source": "", "Dir": "." }, { "Key": "ec2-instance", "Source": "./modules/aws-ec2-instance", "Dir": "modules/aws-ec2-instance" }, { "Key": "hello", "Source": "registry.terraform.io/joatmon08/hello/random", "Version": "4.0.0", "Dir": ".terraform/modules/hello" } ]}
The
aws-ec2-instance
module refers to a local module, so Terraform refers directly to the module's configuration found within themodules/aws-ec2-instance
directory in the example repository. This means that if you make changes to a local module, Terraform will recognize them immediately.Because the
hello
module is remote, Terraform downloaded the module from its source and saved a local copy in the.terraform/modules/hello
directory when you initialized your workspace. Open the files in.terraform/modules/hello
to view the module's configuration. These files are intended to be read-only, like the other contents in.terraform
. Do not modify them. Terraform only updates a remote module when you runterraform init -upgrade
orterraform get
.The
.terraform/providers
directory stores cached versions of all the configuration's providers.View the
.terraform/providers
directory. When you ranterraform init
earlier, Terraform downloaded the providers defined in your configuration from the provider's source (defined by therequired_providers
block) and saved them in their respective directories, defined as[hostname]/[namespace]/[name]/[version]/[os_arch]
.$ tree .terraform/providers.terraform/providers└── registry.terraform.io └── hashicorp ├── aws │ └── 5.43.0 │ └── darwin_amd64 │ └── terraform-provider-aws_v5.43.0_x5 └── random └── 3.6.0. └── darwin_amd64 └── terraform-provider-random_v3.6.0_x5
Update provider and module versions
In terraform.tf
, update the random
provider's version to 3.6.1
.
terraform.tf
terraform { required_version = "~> 1.6" required_providers { ## .. random = { source = "hashicorp/random" version = "3.6.1" } } ## ..}
In main.tf
, update the hello
module's version to 6.0.0
.
main.tf
module "hello" { source = "joatmon08/hello/random" version = "6.0.0" hello = "World" second_hello = random_pet.instance.id secret_key = "secret"}
Reinitialize configuration
Because you updated the provider and module versions, you must re-initialize the configuration for Terraform to install the updated versions.
If you attempt to validate, plan, or apply your configuration before doing so, Terraform will prompt you to re-initialize.
$ terraform validate╷│ Error: Module version requirements have changed││ on main.tf line 38, in module "hello":│ 38: source = "joatmon08/hello/random"││ The version requirements have changed since this module was installed and the installed version (4.0.0) is no longer acceptable. Run "terraform init" to│ install all modules required by this configuration.╵
Re-initialize your configuration to have Terraform upgrade the module to match the new version you configured in the previous step. Terraform will report an error for the provider, however.
$ terraform initInitializing the backend...Initializing modules...Downloading registry.terraform.io/joatmon08/hello/random 6.0.0 for hello...- hello in .terraform/modules/hello Initializing provider plugins...- Reusing previous version of hashicorp/random from the dependency lock file- Reusing previous version of hashicorp/aws from the dependency lock file- Using previously-installed hashicorp/aws v5.43.0╷│ Error: Failed to query available provider packages││ Could not retrieve the list of available versions for provider hashicorp/random: locked provider registry.terraform.io/hashicorp/random 3.6.0 does not│ match configured version constraint >= 3.0.1, 3.6.1; must use terraform init -upgrade to allow selection of new versions╵
Notice that Terraform downloaded the updated module version and saved it in
.terraform/modules/hello
. However, Terraform was unable to update the provider
version since the new provider version conflicts with the version found in the
lock file.
Re-initialize your configuration with the -upgrade
flag. This tells Terraform
to upgrade the provider to the most recent version that matches the version
attribute in that provider's required_version
block.
$ terraform init -upgradeInitializing the backend...Upgrading modules...- ec2-instance in modules/aws-ec2-instanceDownloading registry.terraform.io/joatmon08/hello/random 6.0.0 for hello...- hello in .terraform/modules/hello Initializing provider plugins...- Finding hashicorp/aws versions matching "5.43.0"...- Finding hashicorp/random versions matching ">= 3.0.1, 3.6.1"...- Using previously-installed hashicorp/aws v5.43.0- Installing hashicorp/random v3.6.1...- Installed hashicorp/random v3.6.1 (signed by HashiCorp) Terraform has made some changes to the provider dependency selections recordedin the .terraform.lock.hcl file. Review those changes and commit them to yourversion control system if they represent changes you intended to make. Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to seeany changes that are required for your infrastructure. All Terraform commandsshould now work. If you ever set or change modules or backend configuration for Terraform,rerun this command to reinitialize your working directory. If you forget, othercommands will detect it and remind you to do so if necessary.
View the .terraform/providers
directory structure. Notice that Terraform
installed the updated random
provider version.
$ tree .terraform/providers -L 4.terraform/providers└── registry.terraform.io └── hashicorp ├── aws │ └── 5.7.0 └── random ├── 3.6.0 └── 3.6.1
Open the lock file. Notice that the random
provider now uses version 3.6.1
.
Even though there are two versions of the random
provider in
.terraform/providers
, Terraform will always use the version recorded in the
lock file.
.terraform.lock.hcl
## ...provider "registry.terraform.io/hashicorp/random" { version = "3.6.1" constraints = ">= 3.0.1, 3.6.1" hashes = [ "h1:a+Goawwh6Qtg4/bRWzfDtIdrEFfPlnVy0y4LdUQY3nI=", ## ... "zh:e4aabf3184bbb556b89e4b195eab1514c86a2914dd01c23ad9813ec17e863a8a", ]}
Update module arguments
Since you have updated your provider and module version, check whether your configuration is still valid.
$ terraform validate╷│ Error: Missing required argument││ on main.tf line 37, in module "hello":│ 37: module "hello" {││ The argument "some_key" is required, but no definition was found.╵╷│ Error: Missing required argument││ on main.tf line 37, in module "hello":│ 37: module "hello" {││ The argument "hellos" is required, but no definition was found.╵╷│ Error: Unsupported argument││ on main.tf line 41, in module "hello":│ 41: hello = "World"││ An argument named "hello" is not expected here. Did you mean "hellos"?╵╷│ Error: Unsupported argument││ on main.tf line 42, in module "hello":│ 42: second_hello = random_pet.instance.id││ An argument named "second_hello" is not expected here.╵╷│ Error: Unsupported argument││ on main.tf line 44, in module "hello":│ 44: secret_key = "secret"││ An argument named "secret_key" is not expected here.╵
The new version of the hello
module expects different arguments from the old
version. Replace the entire module "hello"
block with the following:
main.tf
module "hello" { source = "joatmon08/hello/random" version = "6.0.0" hellos = { hello = random_pet.instance.id second_hello = "World" } some_key = "secret"}
Re-validate your configuration.
$ terraform validateSuccess! The configuration is valid.
Now your Terraform workspace is initialized and ready to be applied.
Initialize your Terraform workspace with terraform init
when:
You create new Terraform configuration and are ready to use it to create a workspace and provision infrastructure.
You clone a version control repository containing Terraform configuration, and are ready to use it to create a workspace and provision infrastructure.
You add, remove, or change the version of a module or provider in an existing workspace.
You add, remove, or change the
backend
orcloud
blocks within theterraform
block of an existing workspace.
Next steps
Over the course of this tutorial, you initialized a Terraform configuration with
both local and remote modules, explored the .terraform
directory, and updated
your provider and module versions. These steps were integral to understanding
the mechanisms underlying terraform init
.
For more information on topics covered in this tutorial, check out the following resources.
- Complete the Lock and Upgrade Provider Versions tutorial.
- Complete the Migrate State to HCP Terraform tutorial.
- Read more about
init
in the documentation.