Featured image of post Understanding Terraform State Management in Azure: The Basics

Understanding Terraform State Management in Azure: The Basics

Understand Terraform state management on Azure in this beginner's guide. Learn what state files are, why they're essential, and how to manage them effectively with practical commands and best practices for your infrastructure-as-code projects.

Introduction

Hey there Everyone đź‘‹, welcome back to our Terraform on Azure series! If you’ve been following along, you’ve already taken your first steps with Terraform, you’ve learned how to set up your Terraform environment, created your first Azure resources, and even made changes to your infrastructure. Great work so far!

(If you’re just joining us, you might want to start with our introduction to Terraform on Azure to get up to speed.)

So What are We Learning Today?

In our previous article, you deployed your first Terraform project, creating multiple Azure resources and witnessing the power of Infrastructure as Code. During that process, you may have noticed a file called terraform.tfstate appearing in your project directory. This file is the focus of our discussion today, as we explore one of Terraform’s most crucial concepts: state management.

Think of this state file as Terraform’s “memory” - it’s how Terraform remembers what it’s already created in your Azure account. Without this memory, Terraform wouldn’t know what’s already there versus what needs to be created or changed.

How It All Works Together

Simple visualization showing the relationship between your code, Terraform’s state file, and your Azure resources

The diagram above shows how everything connects:

  1. You write code in your Terraform files (the .tf files)
  2. Terraform compares your code with what’s in its “memory” (the state file)
  3. Terraform then makes only the necessary changes to your Azure resources

What We’ll Cover Today

In this article, we’ll cover:

  1. What Terraform state actually is and why it’s essential
  2. How Terraform uses state to manage your resources effectively
  3. How to view and understand your state file
  4. The basics of local vs. remote state storage
  5. Essential state commands you’ll use regularly

By the end of this guide, you’ll understand how Terraform keeps track of your Azure resources - which will help you avoid common mistakes and feel more confident when building your projects. Let’s dive in!

What is Terraform State?

In the previous article, you’ve seen how Terraform lets you describe your desired Azure resources in configuration files, and how then it automatically creates those resources for you. This declarative approach, where you focus on “what” to deploy rather than “how” to deploy it, makes infrastructure management much simpler.

As we mentioned in the introduction, you likely noticed a file named terraform.tfstate appearing in your project directory. Let’s dive deeper into why this file isn’t just a byproduct—it’s at the heart of what makes Terraform truly powerful.

In simple terms: Terraform state is like your infrastructure’s “memory” or “database” that keeps track of what’s been created and how it’s configured right now.

Think of it like a detailed inventory list. If you were managing a small library, you’d need to know which books you already have before deciding which new ones to buy. Terraform’s state file works the same way—it keeps an inventory of your Azure resources so Terraform knows what exists before making changes.

By default, Terraform stores this state file locally in your project directory, which is perfect for getting started. As your projects grow more complex, you might eventually move to storing state remotely in a shared location like Azure Storage—but don’t worry about that yet! For now, let’s focus on understanding how state works and why it’s so important for your projects.

Taking a Look at the Terraform State File

Before we explore why the state file is so important, let’s take a peek at what it actually contains. When we ran our terraform apply command in the previous article, Terraform created this JSON file to keep track of everything it creates in Azure.

Terraform State File in Project

Here you can see what the terraform.tfstate file looks like in a real project environment. Notice how it’s shown in the VS Code explorer alongside your configuration files (main.tf). The red arrow points to the state file, which gets created in the same directory after you run Terraform commands.

Here’s a simplified example of what you might find in that file after creating a resource group:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
  "version": 4,
  "terraform_version": "1.0.0",
  "resources": [
    {
      "mode": "managed",
      "type": "azurerm_resource_group",
      "name": "example",
      "provider": "provider[\"registry.terraform.io/hashicorp/azurerm\"]",
      "instances": [
        {
          "schema_version": 0,
          "attributes": {
            "id": "/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/example-resources",
            "location": "australiaeast",
            "name": "example-resources",
            "tags": {}
          }
        }
      ]
    }
  ]
}

Now this might look complex, but it contains crucial information, notice:

  • The resource type is (azurerm_resource_group)
  • Your chosen name for this resource in Terraform (example)
  • The actual Azure resource ID (starting with /subscriptions/...)
  • Properties like location, name, and tags

For more complex resources like the virtual machine we created in the previous article, the state file would contain significantly more details—from the VM size to network interface IDs, disk configurations, and more.

The Fundamental Problem State Solves

You might be wondering, “Why does Terraform need to keep this separate file, can’t we just use our configuration file?” This is one of the most important concepts to understand about Terraform, and it explains why state management is mentioned so frequently in HashiCorp documentation.

Think about it this way:

  1. Your configuration files (.tf files) describe what you want to exist
  2. The actual Azure environment contains what currently exists
  3. Terraform needs to determine the difference between these two to know what actions to take

The state file bridges this gap by providing Terraform with:

  • A record of which Azure resources it’s responsible for managing
  • The current properties and relationships of those resources
  • A way to map resources in your configuration to real resources in Azure

Without state, Terraform would face a fundamental challenge: how to determine what exists, what needs to be created, what needs to be updated, and what needs to be deleted.

Why Terraform Can’t Just “Look at Azure”

A common question is, “Why doesn’t Terraform simply query Azure to see what’s there?” This seems logical, but it creates several significant problems that state helps solve:

1. Resource Tracking: Knowing What to Manage

Imagine you have hundreds of resources in Azure, but only some were created with Terraform:

Without state: Terraform would see all Azure resources but wouldn’t know which ones it should manage. It would have no way to tell if a VM was created through Terraform or manually through the portal.

With state: Terraform maintains an inventory of exactly which resources it’s responsible for. When you run terraform plan or apply, it only considers resources it has previously created or has been explicitly told to manage.

For example, if your Azure subscription contains 50 virtual machines but Terraform state only tracks 5 of them, Terraform will only manage those 5 VMs and ignore the rest.

2. Performance: Working Efficiently at Scale

Consider our previous example where we created a resource group, virtual network, subnet, network security group, and virtual machine:

Without state: For each operation, Terraform would need to:

  • Query your entire Azure subscription for all possible resource types!
  • Compare each resource with your configuration
  • Try to guess which Azure resources correspond to your configuration
  • Perform this process repeatedly for every resource type

This would become exponentially slower as your Azure environment grows.

With state: Terraform:

  • Knows exactly which resources to check (the ones in its state file)
  • Makes targeted API calls only for those specific resources
  • Can quickly determine what’s changed and what actions are needed

For example, when changing just the VM size as we did in the previous article, Terraform didn’t need to rediscover your entire network setup—it already knew about those resources and could focus exclusively on the VM change.

3. Dependencies: Understanding Resource Relationships

Remember how we created a VM that depended on a network interface, which depended on a subnet, which depended on a virtual network?

Without state: Terraform would struggle to understand these relationships. It would have to infer dependencies by analyzing resource properties, which is error-prone and may not capture all dependency types.

With state: Terraform records explicit and implicit dependencies between resources. This enables it to:

  • Create resources in the correct order (resource group first, then networking, then compute)
  • Update resources in a sequence that respects their dependencies
  • Delete resources in reverse dependency order to avoid orphaned resources

For example, when we created our VM, Terraform knew it needed to create the resource group first, then the virtual network, subnet, and network interface before it could create the VM itself.

In summary: State is what allows Terraform to efficiently track, manage, and understand your infrastructure without having to rediscover everything each time you make a change.

Important Cautions About State Files

Now that you understand why state is crucial, it’s important to know how to handle it properly:

  1. Never Edit State Manually: The state file has a specific structure that Terraform relies on. Manual edits can confuse Terraform about what exists in your environment.

  2. Keep It Secret, Keep It Safe: If you’re using version control like Git, consider adding .tfstate files to your .gitignore to prevent accidentally committing them to public repositories.

  3. Be Careful with Sensitive Data: Even when using Terraform’s sensitive attribute, secrets still appear in plaintext in your state file. For real projects, use Azure Key Vault or other external secret management solutions instead of hardcoding credentials.

  4. Consider Remote State: For team environments or important projects, storing state remotely (which we’ll discuss later) provides better security and collaboration capabilities.

Now that we’ve covered what Terraform state is and why it matters, let’s get practical and look at how you can actually view and work with your state files using Terraform’s built-in commands.

Viewing Your Terraform State

Now that you understand what Terraform state is and why it’s important, let’s explore how you can actually look at what’s in your state file. While in the previous section we saw a glimpse of the raw JSON content of the terraform.tfstate file, Terraform provides some simple commands that allow you to see what resources it’s tracking in a more human-readable format, without having to parse the JSON directly.

The terraform show Command

The simplest way to view your current state is with the terraform show command. This displays all resources Terraform is managing in a readable format.

Let’s try it:

  1. Open your terminal or command prompt
  2. Navigate to your Terraform project directory (where you created the VM in our previous article)
  3. Run:
1
terraform show

You’ll see output that looks something like this (abbreviated for clarity):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# azurerm_resource_group.rg:
resource "azurerm_resource_group" "rg" {
    id       = "/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/myTFResourceGroup"
    location = "australiaeast"
    name     = "myTFResourceGroup"
}

# azurerm_virtual_network.vnet:
resource "azurerm_virtual_network" "vnet" {
    address_space       = [
        "10.0.0.0/16",
    ]
    location            = "australiaeast"
    name                = "myTFVNet"
    resource_group_name = "myTFResourceGroup"
    # ... other properties ...
}

# azurerm_windows_virtual_machine.vm:
resource "azurerm_windows_virtual_machine" "vm" {
    admin_username        = "adminuser"
    location              = "australiaeast"
    name                  = "myTFVM"
    resource_group_name   = "myTFResourceGroup"
    size                  = "Standard_F4"  # Note this is the size we changed in the previous article
    # ... many more properties ...
}

This output shows you all the resources Terraform is managing, along with their current properties. Notice how it includes the VM size we changed in the previous article ("Standard_F4") — this confirms that Terraform is tracking the updated configuration.

Getting a Resource List with terraform state list

If you just want to see a simple list of resources without all their properties, use:

1
terraform state list

For our project, you’d see something like:

1
2
3
4
5
6
7
azurerm_resource_group.rg
azurerm_virtual_network.vnet
azurerm_subnet.subnet
azurerm_network_security_group.nsg
azurerm_subnet_network_security_group_association.subnet_nsg_assoc
azurerm_network_interface.nic
azurerm_windows_virtual_machine.vm

This provides a quick overview of everything Terraform is managing without overwhelming you with details. It’s particularly useful when you have many resources and need to find the exact name of a specific one.

Looking at a Specific Resource

If you’re interested in the details of just one resource, you can use:

1
terraform state show azurerm_windows_virtual_machine.vm

This will show you only the information about your virtual machine, which is helpful when you’re focused on a specific part of your infrastructure.

When to Use These Commands

These commands are most useful when:

  1. Troubleshooting issues - If something isn’t working as expected, looking at the state can help you understand what Terraform thinks exists
  2. Verifying changes - After making changes, you can check that they were applied correctly
  3. Learning about resources - You can discover all the properties Azure assigns to resources, even ones you didn’t explicitly configure
  4. Getting resource IDs - If you need to reference Azure resource IDs for other tools or scripts

For example, if you’ve just changed your VM size and want to verify that Terraform updated it correctly, you could run:

1
terraform state show azurerm_windows_virtual_machine.vm | grep size

This would show you just the size property, confirming whether it’s now set to “Standard_F4” as expected.

A Word of Caution

While these commands are perfectly safe to use (they’re read-only and don’t modify your infrastructure or state), remember that:

  1. Terraform state might contain sensitive information, so be careful when sharing command output
  2. These commands only show what Terraform knows about - if someone made changes directly in Azure, those might not be reflected until you run terraform refresh (which we’ll cover in a later article)

Reading state is helpful, but to truly understand how Terraform works, let’s see how the state file changes when we modify our infrastructure. This hands-on example will make the concept more concrete.

Seeing State Changes in Action

Now that you know how to view your state, let’s see how it changes when you modify a resource. This practical example will help you understand how Terraform tracks changes.

Let’s say we have our resource group in Australia East:

1
2
3
4
resource "azurerm_resource_group" "rg" {
  name     = "myTFResourceGroup"
  location = "Australia East"
}

After running terraform apply, we can check the current state:

1
2
3
4
5
6
7
$ terraform state show azurerm_resource_group.rg
# azurerm_resource_group.rg:
resource "azurerm_resource_group" "rg" {
    id       = "/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/myTFResourceGroup"
    location = "australiaeast"
    name     = "myTFResourceGroup"
}

Now, let’s change the location to Australia Southeast in our configuration file:

1
2
3
4
resource "azurerm_resource_group" "rg" {
  name     = "myTFResourceGroup"
  location = "Australia Southeast"
}

After running terraform apply again, we can check our state:

1
2
3
4
5
6
7
$ terraform state show azurerm_resource_group.rg
# azurerm_resource_group.rg:
resource "azurerm_resource_group" "rg" {
    id       = "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/myTFResourceGroup"
    location = "australiasoutheast"
    name     = "myTFResourceGroup"
}

Notice how the location in the state file has been updated to match our configuration change. This shows how Terraform keeps its state file in sync with both your configuration and the actual resources in Azure.

This simple example demonstrates why state is so important - it allows Terraform to track the changes you make and apply them precisely. With a clear picture of how state captures infrastructure changes, let’s explore where and how Terraform stores this important information by default.

Understanding Local State

When you start using Terraform, it automatically stores your state locally—right in your project directory. This approach, known as “local state,” is Terraform’s default behavior and the simplest way to get started. Let’s explore what this means for you as you begin your Terraform journey.

Local Terraform State Workflow

This diagram shows the default local state workflow. Notice how everything needed to manage your infrastructure—configuration files, Terraform itself, and the state file—all reside on your local machine. When you run terraform apply, Terraform reads both your configuration files and the local state file, compares them to determine what changes are needed, then communicates with Azure to implement those changes.

What is Local State?

Local state simply means that Terraform stores information about your infrastructure in files on your computer:

  1. terraform.tfstate: Your current state file
  2. terraform.tfstate.backup: A backup of the previous state

These files are created automatically in the same directory as your Terraform configuration files (.tf files). Every time you run terraform apply, Terraform reads the current state, makes a backup, and then updates the state with any changes.

If you look in your project directory after running Terraform, you’ll see these files:

1
2
3
4
5
$ ls -la
drwxr-xr-x  ...  .terraform/
-rw-r--r--  ...  main.tf
-rw-r--r--  ...  terraform.tfstate
-rw-r--r--  ...  terraform.tfstate.backup

When to Use Local State

Local state works well in several situations:

  1. Learning and Experimenting: As you work through this series and learn Terraform, local state is perfect for testing and experimentation
  2. Personal Projects: For infrastructure you manage by yourself
  3. Small-Scale Projects: When you’re managing a handful of resources rather than hundreds
  4. Development Environments: Non-critical environments where you’re testing configurations

For the Azure VM environment we built in the previous article, local state is entirely appropriate—it’s a relatively small project that you’re using to learn Terraform.

Important Considerations for Local State

While local state is simple to use, there are some important things to keep in mind:

Security Considerations

  1. State Contains Sensitive Data: Your state file might contain sensitive information like database passwords or storage access keys, depending on what resources you’re managing
  2. Not Encrypted: The state file is stored as plaintext (unencrypted) on your computer
  3. Version Control Caution: Never commit your .tfstate files to public repositories (add them to .gitignore)

Basic Limitations

  1. Single-User Only: Only one person can safely make changes at a time
  2. Limited Backup: Only the previous state is automatically backed up
  3. No Locking: Nothing prevents two Terraform processes from modifying state simultaneously (though this isn’t an issue when working alone)

Best Practices for Local State

If you’re using local state for your projects, here are some simple best practices:

  1. Regular Backups: Occasionally copy your state files to a secure location as a backup
  2. Document Your Project: Keep notes about what you’ve created, especially for longer-term projects
  3. Be Consistent: Always run Terraform from the same directory to avoid state confusion

These practices will help you maintain your Terraform projects successfully while learning and experimenting with Azure resources.While local state works well for getting started, it’s good to be aware of some challenges you might encounter. Let’s look at common issues and their solutions.

Common State File Issues

While local state is straightforward to use, you may occasionally encounter challenges that require troubleshooting. Here’s what to do if they occur:

What to Do If You Accidentally Delete Your State File

If you delete your terraform.tfstate file, Terraform loses its memory of what it created. When you try to run terraform plan commands after deleting your state file, you’ll see something like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
$ terraform plan

Terraform will perform the following actions:

  # azurerm_resource_group.rg will be created
  + resource "azurerm_resource_group" "rg" {
      + id       = (known after apply)
      + location = "australiaeast"
      + name     = "myTFResourceGroup"
    }

  # azurerm_virtual_network.vnet will be created
  + resource "azurerm_virtual_network" "vnet" {
      + address_space       = [
          + "10.0.0.0/16",
        ]
      # ... more attributes ...
    }

Plan: 7 to add, 0 to change, 0 to destroy.

Notice how Terraform plans to recreate all resources, even though they already exist in Azure. This happens because without the state file, Terraform has no way to know these resources already exist.

When this happens:

  1. Check for a Backup: The first and easiest step is to check if you have a backup state file named terraform.tfstate.backup. If you find it, simply rename it to terraform.tfstate:
1
2
3
$ cp terraform.tfstate.backup terraform.tfstate
$ terraform plan
No changes. Your infrastructure matches the configuration.

After restoring the backup, Terraform correctly recognizes that your resources already exist.

  1. Advanced Recovery (Terraform Import): In the unfortunate scenario that you’ve lost both the terraform.tfstate and the terraform.tfstate.backup file, you might need to explore terraform import. This is a more advanced Terraform feature that allows you to bring existing Azure resources under Terraform’s management. However, it requires you to know the exact resources defined in your Terraform configuration and their corresponding Azure resource IDs. Even then, it might not fully reconstruct the original state, especially for complex resources. We’ll delve into terraform import in a later, more advanced article.

What to Do If You’ve Edited the State File Manually

Manually editing the terraform.tfstate file is strongly discouraged as it can lead to inconsistencies and errors in Terraform’s understanding of your infrastructure. If you accidentally change a resource ID in the state file, you might see an error like this::

1
2
3
$ terraform plan
Error: Error refreshing state: 1 error occurred:
	* azurerm_resource_group.rg: Resource group with ID "/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/INCORRECTNAME" was not found

This error occurs because Terraform is trying to find a resource that doesn’t exist (because you changed the ID). When you encounter this:

  1. Restore from Backup: The safest solution is to restore from your backup file:
1
2
3
$ cp terraform.tfstate.backup terraform.tfstate
$ terraform plan
No changes. Your infrastructure matches the configuration.
  1. Advanced Recovery Options: If a backup isn’t available, there are more advanced techniques you could explore, such as using terraform import as we said above or even attempting to recreate the state by carefully aligning your configuration with your existing Azure resources. However, these methods can be complex and may not guarantee a full recovery.

As you’ve seen, local state has some limitations and potential challenges. Fortunately, Terraform offers a more resilient alternative: remote state storage. Let’s explore this option for more advanced scenarios.

Understanding Remote State

As your Terraform skills grow and your Azure projects become more complex, you’ll eventually outgrow local state files. Let’s briefly explore the next step in your Terraform journey: remote state storage.

Remote Terraform State Workflow

This diagram illustrates how remote state enables team collaboration. Notice the key differences from the local workflow: multiple developers can work with the same infrastructure, configuration files are typically stored in a central repository like GitHub, and most importantly, the state file is stored in Azure Storage rather than on any individual’s computer.

What is Remote State?

Remote state means storing your Terraform state file in a central location rather than on your local computer. For Azure, this typically means using Azure Blob Storage as your backend, though Terraform supports other remote backend options like HashiCorp Consul.

This changes how Terraform works with your state:

  1. During initialization (terraform init), Terraform sets up the connection to your Azure Blob Storage
  2. Before any operation (terraform plan or terraform apply), Terraform downloads the latest state from Azure Blob Storage
  3. Terraform compares your configuration against the remote state to determine necessary changes
  4. After applying changes, Terraform updates the remote state file to reflect the new infrastructure reality
  5. Azure Blob Storage maintains versioning of your state files, providing a history of changes

Why Consider Remote State?

Remote state solves several important challenges you’ll face as your Terraform usage matures:

Team Collaboration

When multiple people need to work on the same infrastructure:

  • Everyone gets the latest state automatically
  • Changes by one team member are visible to others
  • No need to manually share state files

Enhanced Security

Remote state provides better protection for your infrastructure information:

  • Azure Storage offers encryption at rest
  • Access can be controlled with Azure RBAC
  • Sensitive data is not stored on individual computers

State Locking

Remote backends typically support locking, which prevents two people from making conflicting changes simultaneously. This becomes crucial when working in teams.

Reliable Backups

Azure Blob Storage provides:

  • Automatic redundancy for your state files
  • Point-in-time recovery options
  • Protection against accidental deletion

When Will You Need Remote State?

You should consider moving to remote state when:

  • You start working with others on the same infrastructure
  • Your projects become more complex or critical
  • You need to manage environments across multiple computers
  • You’re implementing CI/CD pipelines for your infrastructure

For now, as you’re learning Terraform, local state is perfectly adequate. We mention remote state here so you’re aware of what’s ahead on your learning journey. In future projects, as your infrastructure needs grow, you’ll find remote state becomes increasingly valuable.

What is a Backend?

Throughout this article, we’ve talked about local state and remote state. If you’re reading HashiCorp’s documentation, you’ll encounter a more technical term for the location where Terraform stores its state file: a backend.

A backend simply refers to the location where Terraform stores its state file. When you’ve been working locally, Terraform has been using what is called the local backend, storing your terraform.tfstate and terraform.tfstate.backup files directly in your project directory.

For more advanced scenarios, you can configure a remote backend, which stores your state in a centralized location, such as Azure Blob Storage or HashiCorp Consul.

We won’t delve into the configuration details of how to set up a remote backend here. This is a topic for a more advanced article. Just know that it exists and it’s possible to implement when you’re ready.

Now that you’re familiar with both local and remote state options, you might be wondering, “With all the benefits of a remote backend, should I move to using one now?”

For now, while you’re mastering the fundamentals of Terraform, local state is perfectly sufficient. As your projects become more important or as you start collaborating with team members, consider transitioning to remote state.

Conclusion

Congratulations! You’ve just completed a crucial step in your Terraform journey by mastering the concept of state management. Let’s recap what we’ve learned:

Key Takeaways About Terraform State

  • State is Terraform’s Memory: It stores information about what resources Terraform is managing in your Azure environment
  • The State File Maps Terraform to Azure: It connects your configuration files to actual resources in the cloud
  • Viewing State is Simple: Commands like terraform show and terraform state list let you see what Terraform is tracking
  • Local State Works for Learning: As you’re getting started, local state files provide a simple way to work with Terraform
  • Remote State for Collaboration: When you’re ready to collaborate or work on larger projects, remote state will be your next step

Understanding state is fundamental to using Terraform effectively. It’s the mechanism that allows Terraform to track your infrastructure over time and make precisely targeted changes when needed.

Putting Your Knowledge into Practice

Before you move on to the next article, take some time to experiment with what you’ve learned:

  • Try viewing the state of your existing resources with terraform show
  • Look at how changing resource configurations affects your state
  • Practice the habit of keeping your state file secure

Finally don’t be afraid to experiment, make mistakes, and learn from them. That’s the beauty of infrastructure-as-code – you can always tear it down and start again!

When you are ready to take the next step in your Terraform journey, move to the next article Terraform Dependencies

Stay strong đź’Ş, and happy Terraforming!