How to Use Terraform State List to Filter and Audit State
terraform state list is the fastest way to see everything Terraform is tracking, but its real value only shows up once you know how to filter it. This piece covers the command itself, how to narrow results with resource addresses, and how a filtered inventory becomes a practical tool for auditing a growing state file.
terraform state list prints every resource address Terraform is tracking, sorted by module depth first, and then alphabetically.Once a Terraform project outgrows a handful of resources, it starts to get challenging to track everything it manages. terraform state list is a solution, printing every resource address currently tracked in your state file for a complete, current picture of what Terraform actually controls, without touching a single attribute or running a plan.
However, the first time you run it against a real project, you start to hit its limits, as hundreds of lines scroll past, with root resources mixed in with deeply nested submodules and no obvious way to find the one thing you were looking for.
You only really get value once you know how to narrow it down, which is what this guide covers, along with the syntax and how a filtered list becomes part of your habitual auditing rather than a one-off lookup.
What Terraform state list does
terraform state list prints every resource address Terraform is currently tracking, nothing more: no attribute values, no resource IDs, no configuration detail, just the address of each managed resource, one per line. Because it only reads state and never writes to it, it doesn't generate the backup files that modification commands create, so it's safe to run against production state without any risk of altering it.
It is the narrowest of several terraform state subcommands, alongside terraform state show, terraform state rm, and terraform state mv.
For a small project, the output is easy to scan. For a project with thousands of resources across dozens of modules, the same command produces a wall of text that answers what exists but doesn't help you find the one resource you need. At this point, filtering comes in.
What terraform state list shows and does not show
terraform state list shows resource addresses only, not the AMI ID, the ARN, the current tags, or any other attribute Terraform has recorded, and not whether the live resource in your cloud provider still matches what Terraform believes it deployed.
It's only the first step, pointing you to the specific address that terraform state show can then inspect in full. We cover exactly what state show reveals, and its own limits, in our guide to terraform state show.
An address tells you a resource's type, its local name, and its module path if it lives inside one, but it's a pointer into state rather than the state data itself. Two projects can share an aws_instance.web address that looks identical while pointing at completely different instances in different accounts. It's unique within its own state file, not universal.
Terraform state list command syntax and basic usage
Run the above with no address argument and Terraform lists every resource in state. Provide one or more address patterns, and it narrows the output to whatever matches (which is covered next).
Youll encounter two command-line options in your day-to-day work:
-state=pathis a legacy option for the local backend only, pointing at an alternate local state file instead of the defaultterraform.tfstate.-id=idflips the lookup around, letting you search by a resource's ID instead of its address, useful when a ticket gives you an ID and you need to know where it lives in your terraform code.
Results are sorted by module depth first and then alphabetically, so root module resources appear before anything nested. That order is stable across current Terraform releases.
Filtering results with resource addresses
Filtering by resource type or name narrows the list down to matching addresses. Running the command below against a state file with multiple instances returns only the matching entries, indexed if created with count or keyed if created with for_each.
Filtering by module works the same way, and it's the most useful filter once a project has any real module structure. Running it against a module returns every resource inside that module and any submodules nested underneath it, so a load balancer module wrapping its own security group submodule shows both addresses.
The -id option flips the lookup around entirely. Instead of starting from an address, you start from a resource ID, the kind mentioned in a ticket or a cloud console, and ask Terraform where that thing lives.
That turns a bare ID into a one-line answer instead of a manual search through every module.
Piping terraform state list into other tools
HashiCorp built the plain text output deliberately, so it pipes cleanly into standard command line tools rather than needing a dedicated flag for machine-readable output the way terraform show -json does. Counting resources of a given type is one line, and finding everything under a specific module works the same way.
On PowerShell, Select-String swaps in for grep. The output is plain text, so one address per line, awk, sed, and simple shell loops all work without special handling, which is why state list appears inside scripts and CI checks far more often than terraform show -json.
Using Terraform state list to audit and inventory your state
A filtered terraform state list output is the starting point for a surprising amount of operational work.
Before a migration, running it against the module you're about to move confirms exactly which resources need new addresses, so nothing gets left behind or duplicated.
As a compliance check, filtering by resource type across a whole state file gives you a quick inventory of everything of that type under Terraform's management, useful evidence when someone asks whether a service is fully managed by code.
It also surfaces resources no longer needed.
A state list filtered to a decommissioned module that still returns entries signals something was removed from configuration without a corresponding terraform state rm or a real terraform apply, and may still be sitting there, unmanaged and quietly costing money. None of this replaces the backend and CI/CD considerations of running this safely at scale, which our practical guide to Terraform state covers in full.
Common Terraform state list errors and gotchas
The most common mistake is made with address syntax, particularly around resources created with count or for_each.
An index or a for_each key with special characters needs quoting in most shells, so a line like aws_instance.bar["blue"] typed unquoted gets partially interpreted by the shell before Terraform sees it, usually returning no results and no error, which looks identical to a genuinely empty match.
If a filter returns nothing, run terraform state list with no arguments first to confirm the resource exists before concluding your pattern was wrong.
Remote backends introduce a quieter gotcha, which reveals more about performance than correctness. Any reads against a remote state backend (whether Amazon S3, Google Cloud Storage, or Azure Blob Storage) add a network round trip a local backend doesn't have, so state list against a large remote state file can feel noticeably slower, particularly when run repeatedly inside a loop or a CI job.
However, that slowness is a characteristic of remote state storage generally, not this command specifically.
Where Stategraph fits into state inventory and auditing
terraform state list is designed to provide you with a text-based inventory. As mentioned, this inventory can become unwieldy once the state file grows large enough that a flat, sorted list stops being something you can filter through effectively.
Stategraph stores that same inventory as a queryable graph rather than a flat file, so the information state list gives you as scrolling text becomes something you can browse and filter visually, with relationships between resources already mapped rather than inferred from module paths alone.
It's a complement to Terraform's own state management, not a replacement for terraform apply, and it stays scoped to state rather than CI/CD orchestration or policy enforcement.
Conclusion
terraform state list is often the first command Terraform users try during audits and migrations, or when they're curious about what a project manages and filtering by resource type, module, or ID will turn a wall of text into something usable.
Once state grows past what can be represented in a flat list, that same inventory is worth exploring as a graph.
Read Stategraph's documentation and our guide to how Stategraph works to discover why storing infrastructure state as a dependency graph makes it more easier to query, audit, analyze, and compose.
Terraform state list FAQs
Does terraform state list modify the state file?
No. It's a read-only command, and it doesn't generate the backup files that state modification commands like terraform state rm and terraform state mv create before they run.
Can you filter terraform state list output by module?
Yes. Passing a module path such as module.elb as the address argument returns every resource inside that module, along with any submodules nested inside it.