What is Terraform state?
Brendan Thompson • 30 January 2023 • 5 min read
What is Terraform state exactly and what does it do? If we consider the below diagram which shows us all the Parts of Terraform State is the final piece of the flow. This is where every action we perform in Terraform records its results. It allows us to store a representation of our environments and the resources within those environments. This is incredibly helpful not only for engineering purposes but also security and governance as it gives us a way to track change and understand the current state of play. State is at the core of Terraform and is one thing that sets it apart from other Infrastructure-as-Code (IaC) solutions.

Figure 1 — Parts of Terraform - State
So when we create a virtual machine or a network a JSON representation of the resource is created in our state file. For this post, we don't care where that state file is located only that it exists.
Let's have a look at what an empty state file looks like:
{
"version": 4,
"terraform_version": "1.3.2",
"serial": 1,
"lineage": "af5370f0-30e4-5e77-0819-b893a4ac6d13",
"outputs": {},
"resources": [],
"check_results": []
}
Let's walk through the components:
version
— this is the state schema version it tells Terraform Core what version of the schema to use when reading/writing to the state fileterraform_version
— the version of Terraform that was used to create this state fileserial
— the version of this particular state file, this will increment every time a Terraformapply
is run and a change in state occurslineage
— this is a unique identifier for this state file in a given backend, this should only change if the state is moved to a new backendoutputs
— all outputs provided by the Terraform code that created this state fileresources
— all resources that were createdcheck_results
— the status of condition checks such as; Preconditions, Postconditions and Variable Validation
Let's have a look at some of these objects in further detail below.
Outputs
Below we can see that the outputs
object in our state file now has a single object hello
. This
object contains the value and the type of the output and no additional information.
{
...
"outputs": {
"hello": {
"value": "world",
"type": "string"
}
},
...
}
The Terraform code below is what was used to produce that output
object in our state file.
locals {
value = "world"
}
output "hello" {
value = local.value
}
So for every output
that we create in Terraform a new object will be produced for us in our state
file. Now, with an output,
there are a few more properties that we can set; sensitive
and
description
. It might surprise you to know that of those two only sensitive
is stored in state
and only when it's true, the description
is purely for us engineers to read.
Resources
{
...
"resources": [
{
"mode": "managed",
"type": "scratch_string",
"name": "this",
"provider": "provider[\"registry.terraform.io/brendanthompson/scratch\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"description": null,
"id": "2a1a55c6-9f70-11ed-826a-aacb117da4fa",
"in": "world"
},
"sensitive_attributes": [],
"dependencies": [
"module.string.random_string.this"
]
}
]
},
{
"module": "module.string",
"mode": "managed",
"type": "random_string",
"name": "this",
"provider": "provider[\"registry.terraform.io/hashicorp/random\"]",
"instances": [
{
"schema_version": 2,
"attributes": {
...
},
"sensitive_attributes": []
}
]
}
],
...
}
module
— the address to the module being used to provision this resource(s)mode
— identifies if the resource is aresource
block,data
block or invalidtype
— the type of resourcename
— the name of the resource being createdprovider
— the full pathway to the providerinstances
— one or more instances of a given resourcestatus
— the status of the resource instance, an example would bestatus: "tainted"
if the resource instance was taintedschema_version
— the resource-specific schema version within the providerattributes
— the attributes as defined by the provider that was set for the given resourcesensitive_attributes
— an array of paths withinattributes
to mark as sensitivedependencies
— an array of resource addresses that this resource is dependent on
As you can see there are a few more attributes associated with our resources when they're written to state.
Check Results
The final piece we will talk about is the checked_results
array, this tells us about any custom
configuration checks we might be using in our Terraform.
{
...
"check_results": [
{
"object_kind": "output",
"config_addr": "output.hello",
"status": "pass",
"objects": [
{
"object_addr": "output.hello",
"status": "pass"
}
]
}
]
}
object_kind
— the kind of resource the checks were performed on; Invalid Condition, Resource Precondition, Resource Postcondition, Output Preconditionconfig_addr
— the pathway in the state of the resource we are performing the checks onstatus
— the aggregate result of all checks performed on the resourceobjects
— an object for each check performed on the resourceobject_addr
— the state path of the specific object being checkedstatus
— the result of the check for this single object
Closing Out
In this article, we have gone through what state is, and the components of the state file itself. This should help you better understand what is going on when we run the different phases of Terraform. Terraform State allows us to have a point-in-time view of our infrastructure which allows us to do powerful things such as comparing our desired state (our code), to our perceived state (the state file) to reality (the resources within the platform/service). This can be surmised by the below diagram.

Figure 2 — Phases of State