Terraform Tutorial — State File Structure
Understanding the JSON structure of the state file helps you debug issues and understand what Terraform is tracking.
State File Anatomy
A simplified terraform.tfstate:
{
"version": 4,
"terraform_version": "1.7.0",
"serial": 5,
"lineage": "abc12345-6789-def0-1234-567890abcdef",
"outputs": {
"bucket_name": {
"value": "my-app-bucket-12345",
"type": "string"
}
},
"resources": [
{
"mode": "managed",
"type": "aws_s3_bucket",
"name": "main",
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
"instances": [
{
"attributes": {
"id": "my-app-bucket-12345",
"arn": "arn:aws:s3:::my-app-bucket-12345",
"bucket": "my-app-bucket-12345",
"region": "us-east-1",
"tags": {
"Environment": "dev"
}
}
}
]
}
]
}
Key Fields
| Field | Purpose |
|---|---|
version |
State format version (currently 4) |
terraform_version |
Version of Terraform that wrote this state |
serial |
Incremented on every state change (used for locking) |
lineage |
UUID that identifies this state’s history |
outputs |
All declared outputs and their values |
resources |
Array of every managed resource |
Resource Entry Fields
| Field | Example | Purpose |
|---|---|---|
mode |
"managed" or "data" |
Resource vs data source |
type |
"aws_s3_bucket" |
Resource type |
name |
"main" |
Local name in your config |
provider |
"provider[\"...aws\"]" |
Which provider manages it |
instances |
Array of objects | The actual resource instances |
Resource Address
The combination of type and name forms the resource address:
aws_s3_bucket.main
aws_instance.web
aws_vpc.production
These addresses are used in state commands, targeting, and imports.
The Backup File
Every time Terraform writes a new state, it saves the previous version:
terraform.tfstate ← current state
terraform.tfstate.backup ← previous state
If something goes wrong, you can restore from the backup.
What’s Next?
When teams share state, you need locking to prevent concurrent modifications. Let’s learn about state locking.