Terraform Associate
Deep Dive
State is the core of how Terraform works. Understanding its structure, the locking mechanism for teams, and how to handle drift are recurring topics on the exam.
Contents
The state (terraform.tfstate) is the source-of-truth record Terraform keeps about the resources it manages. It's a JSON file that maps each resource in your configuration to its corresponding real resource in the cloud.
Config → real mapping
Associates aws_vpc.main with vpc-0abc123 in AWS. Without this mapping, Terraform doesn't know which resources to manage.
Diff calculation
To generate the plan, Terraform compares the state with the desired configuration. Without state, it would recreate everything.
Dependency metadata
Stores dependencies between resources to know the correct destroy order.
Attribute cache
Stores computed attributes (such as IDs generated by the cloud) for use in other references.
⚠️ Never edit the tfstate manually
Manually editing terraform.tfstate can corrupt the state and cause Terraform to unexpectedly destroy or recreate resources. Always use the terraform state commands to manipulate the state.
The tfstate file is JSON. Knowing its structure helps you understand how Terraform works internally.
{
"version": 4, // state format version
"terraform_version": "1.6.3", // version of Terraform that generated this state
"serial": 7, // serial number (increments on each apply)
"lineage": "abc-123-...", // unique UUID of this state instance
"outputs": {
"vpc_id": {
"value": "vpc-0abc123def",
"type": "string",
"sensitive": false
}
},
"resources": [
{
"module": "module.vpc", // if it's a child module, otherwise empty
"mode": "managed", // "managed" (resource) or "data" (data source)
"type": "aws_vpc", // resource type
"name": "main", // local name
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
"instances": [ // usually 1, multiple with count/for_each
{
"schema_version": 1,
"attributes": { // ALL of the resource's attributes (including sensitive ones)
"id": "vpc-0abc123def",
"cidr_block": "10.0.0.0/16",
"tags": {"Name": "my-vpc"}
// ... all other attributes
},
"dependencies": [ // resources it depends on
"aws_internet_gateway.main"
]
}
]
}
]
}terraform.tfstate
The main state file. Updated after every apply.
terraform.tfstate.backup
Automatic backup of the state prior to each apply. Only the most recent one.
State locking prevents two Terraform operations from modifying the state simultaneously, which could corrupt it. Terraform tries to acquire the lock before any operation that writes to the state.
| Backend | Supports locking? | Lock mechanism |
|---|---|---|
| Local (default) | ✅ Yes | OS file lock — only protects on the same machine |
| S3 | ✅ Yes* | * Requires use_lockfile = true (1.11+); DynamoDB is the legacy method |
| Azure Storage | ✅ Yes | Native Azure blob lease (automatic) |
| GCS | ✅ Yes | Native GCS object locking (automatic) |
| HCP Terraform | ✅ Yes | Automatic locking on every run (plan/apply) |
| Terraform Enterprise | ✅ Yes | Automatic locking |
| HTTP backend | ⚠️ Optional | Depends on the HTTP server implementation |
💡 S3 locking: use_lockfile
The S3 backend does not lock state by default. Since Terraform 1.11 you enable it with use_lockfile = true: Terraform creates a .tflock file next to the state in the same bucket. The previous method, a DynamoDB table keyed on LockID referenced with dynamodb_table, is deprecated.
# If an apply fails and the lock is left "stuck": # Terraform shows the Lock ID in the error message terraform force-unlock LOCK_ID # ⚠️ Only use this if you're SURE no other apply is in progress # Incorrectly releasing the lock can cause state corruption
Drift occurs when the actual state of infrastructure in the cloud differs from the state recorded in tfstate. This happens when someone modifies the infra manually (via console, cloud CLI, etc.) without going through Terraform.
Drift example
Your tfstate says the instance has instance_type = t3.micro. Someone changed it manually to t3.large from the AWS console.
Risk
If you run terraform apply without detecting the drift, Terraform may revert the manual change or produce unexpected conflicts.
Solution
Run terraform plan -refresh-only to detect and reconcile the drift without applying configuration changes.
# Detect drift (refreshes the state against reality) terraform plan -refresh-only # Possible output: # ~ aws_instance.web # ~ instance_type = "t3.micro" -> "t3.large" (manual change detected) # Accept the drift (update the state to match reality): terraform apply -refresh-only # Revert the drift (apply the configuration as it was): terraform apply # A normal terraform plan also refreshes the state before planning # The difference is that -refresh-only ONLY refreshes, it does not apply config changes
The tfstate stores all of a resource's attributes in plain text, including passwords, API keys, certificates, and other secrets. This is one of the most important reasons to use a remote backend with encryption.
Local backend (default)
The tfstate stays on the developer's disk. If it gets pushed to Git by mistake, all secrets are exposed.
S3 without encryption
The tfstate on S3 without server-side encryption is accessible to anyone with access to the bucket.
S3 with SSE-KMS
Encrypted at rest with KMS. Access controlled by IAM policies. Recommended for production.
HCP Terraform
Automatic encryption at rest. Access controlled by teams and workspace permissions.
🎯 For the exam
sensitive = trueterraform plan -refresh-only detects drift without applying changesDid you get this topic?
Test what you just learned
A team uses the S3 backend to store Terraform state. They have configured the bucket correctly but notice that two team members can run terraform apply at the same time without one blocking the other. What is missing from the configuration?
Put what you learned to the test with original Terraform Associate exam questions.
Start Terraform Associate mock examUnlimited mock exams with the Pro plan
Log in to track your progress.