In this article, we will explore the terraform refresh
command — what it is, how to use it, and the risks of running it.
We will cover:
- What is the terraform refresh command?
- How to use the terraform refresh command
- What to use instead of terrafrom refresh?
Warning: As of Terraform version 0.15.4 and later terraform refresh
command is deprecated because its default behavior is unsafe if you have misconfigured credentials for any of your providers.
The terraform refresh
command is used to reconcile the state file with the actual infrastructure. It updates Terraform’s state to reflect the current real-world state of managed resources.
terraform refresh [options]
With options:
-var 'key=value'
: Sets a variable directly from the command line.-var-file=FILE
: Loads variables from a file.-lock=true/false
: Enables or disables state locking (enabled by default).-lock-timeout=TIMEOUT
: Specifies a duration to wait for the state lock.
By running terraform refresh
after making manual changes to your infrastructure resources, you ensure that your Terraform state file is up-to-date and reflects the current state of your infrastructure resources.
terraform refresh
will not alter any of your real infrastructure but will alter the Terraform state file. It is designed to reconcile any differences from the drift between your infrastructure and the information contained in the state file. It will take into account only objects already in the state file. Any objects outside the state will not be considered and must be imported into the state to be managed by Terraform.
Because the command is included in plan and apply, it typically does not need to be run separately. In fact, Hashicorp recommends you do not use refresh
, except for backward compatibility reasons, for use with Terraform versions prior to v0.15.4.
When you create a terraform plan
or run terraform apply
, Terraform automatically refreshes the state of existing objects (this is the default behavior).
Here are some examples of how terraform refresh
works:
Example 1: Using terraform refresh with AWS S3
Start by writing a Terraform configuration to create an S3 bucket:
resource "aws_s3_bucket" "example" {
bucket = "example-bucket-1234"
acl = "private"
}
Run the terraform init
and terraform apply
to initialize and apply the configuration. This creates an S3 bucket named example-bucket-1234
with the ACL (Access Control List) set to private
.
Go to the AWS Management Console and modify the S3 bucket settings:
- Change the ACL from
private
topublic-read
. - Add a bucket policy to allow public access to the bucket.
Now, run the terraform refresh
command. What happens:
- Terraform queries the current state of the S3 bucket from AWS.
- The local Terraform state file is updated to reflect the manual changes:
- The ACL is now
public-read
. - The bucket policy is updated with the newly added policy.
- The ACL is now
Run terraform plan
to review the differences. Based on the terraform plan
output, you have two options.
Revert to the desired state
Update the configuration (main.tf) to match the original state:
resource "aws_s3_bucket" "example" {
bucket = "example-bucket-1234"
acl = "private"
}
Apply the configuration to reset the changes.
Accept the changes
Update the Terraform configuration to match the new state:
resource "aws_s3_bucket" "example" {
bucket = "example-bucket-1234"
acl = "public-read"
}
If the bucket policy is required, add it to the configuration as well:
resource "aws_s3_bucket_policy" "example" {
bucket = aws_s3_bucket.example.id
policy = <<EOT
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::example-bucket-1234/*"
}
]
}
EOT
}
Apply the updated configuration.
Example 2: Using terraform refresh with Azure VNET
Let’s use Terraform to create a virtual network (VNET) with subnets:
resource "azurerm_virtual_network" "example" {
name = "example-vnet"
address_space = ["10.0.0.0/16"]
location = "East US"
resource_group_name = "example-resources"
}
resource "azurerm_subnet" "example" {
name = "example-subnet"
address_prefix = "10.0.1.0/24"
virtual_network_name = azurerm_virtual_network.example.name
resource_group_name = "example-resources"
}
Run terraform init
and terraform apply
to deploy the VNET and subnet, and our local state file will match the actual state of the deployed infrastructure.
Now, modify the VNET or subnet directly in the Azure portal (or any other cloud provider portal). For example, change the subnet address space from 10.0.1.0/24
to 10.0.2.0/24
.
Run the terraform refresh
command to query the current state of our resources in Azure (or the respective backend) and update the local Terraform state file to reflect the manual change.
After the refresh, run terraform plan
.
Terraform will now detect the difference between the desired state (defined in your main.tf) and the updated state (from the terraform refresh
command). It will show an execution plan to revert or adapt the configuration to match the desired state.
Although terraform refresh
command can be a useful diagnostic tool, here are some concerns associated with its usage:
terraform refresh
updates the Terraform state file with the current real-world infrastructure state. If resources have been changed outside Terraform (e.g., through manual updates), this could result in unanticipated differences. These changes may later cause Terraform to create, modify, or destroy resources unexpectedly during an apply.- It queries every resource defined in the Terraform configuration, which can be time-consuming for large infrastructures. Additionally, if there are many or complex providers, the refresh operation could lead to delays or timeouts, affecting workflow efficiency.
- Frequent or interrupted refresh operations can increase the risk of inconsistencies or corruption in the state file, particularly if there are issues like network interruptions or bugs in the provider APIs. This could lead to errors in subsequent Terraform operations.
The terraform refresh
command was deprecated in Terraform 1.6. You can achieve the same functionality using the --refresh-only
option, which was introduced to the plan
and apply
commands for Terraform versions v0.15.4 and above. Now terraform refresh
command is essentially an alias to the terraform apply -refresh-only -auto-approve
Excluding the auto-approve
option will prompt you for confirmation before the refresh is performed.
Example: How to use terraform apply -refresh-only command
Assume you have a Terraform configuration managing an AWS S3 bucket. The bucket was modified manually (e.g., enabling versioning) outside Terraform, and you want to update the state to reflect this change.
provider "aws" {
region = "us-east-1"
}
resource "aws_s3_bucket" "example" {
bucket = "my-example-bucket"
acl = "private"
}
Initialize Terraform (if not already initialized). Before running the --refresh-only
command, you can preview changes with:
terraform plan -refresh-only
Output indicates the Terraform state is missing the versioning
configuration enabled on the S3 bucket:
Terraform used the selected providers to generate the following execution plan. Any actions below are proposed updates to the state and not your infrastructure.
aws_s3_bucket.example: Refreshing state... [id=my-example-bucket]
~ resource "aws_s3_bucket" "example" {
id = "my-example-bucket"
acl = "private"
+ versioning {
enabled = true
}
}
Plan: 0 to add, 0 to change, 0 to destroy.
Now, run terraform apply -refresh-only
.
Output:
Terraform used the selected providers to generate the following execution plan. Any actions below are proposed updates to the state and not your infrastructure.
aws_s3_bucket.example: Refreshing state... [id=my-example-bucket]
~ resource "aws_s3_bucket" "example" {
id = "my-example-bucket"
acl = "private"
+ versioning {
enabled = true
}
}
Do you want to perform these actions in the state? Only 'yes' will be accepted to approve.
Enter a value: yes
aws_s3_bucket.example: Modifications to state completed after 0s
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
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.
By running terraform refresh after making manual changes to your infrastructure resources, you ensure that your Terraform state file is up-to-date and reflects the current state of your infrastructure resources. This helps to prevent any conflicts or inconsistencies that might occur when Terraform is used to manage the same resources as other tools or manual changes.
We encourage you to explore how Spacelift makes it easy to work with Terraform. If you need help managing your Terraform infrastructure, building more complex workflows based on Terraform, and managing AWS credentials per run instead of using a static pair on your local machine, Spacelift is a fantastic tool. It supports Git workflows, policy as code, programmatic configuration, context sharing, drift detection, and many more great features right out of the box.
If you want to learn more about Spacelift, create a free account today or book a demo with one of our engineers.
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.