Find what’s running outside your Terraform.
Out of State is a local, read-only CLI that compares the resources in an AWS account with the Terraform states you provide.
See what is tracked, what has no match, and which Terraform project manages each resource.
$ oos --profile default --region eu-west-1 --source ./app-infra --source ./shared-infra Out of State · account 123456789012 · eu-west-1 · 2026-11-06 10:42 UTC Scan: complete source ./app-infra (default) ✓ 10:42:00 source ./shared-infra (prod) ✓ 10:42:01 2 import candidate(s): resources with no match in the supplied states analytics-db eu-west-1 rds db.r6g.large postgres 16.2 available created 2025-03-02 legacy-alb eu-west-1 alb internal vpc-0a1b2c3d active created 2024-01-01 3 tracked in state orders-db eu-west-1 rds ./app-infra (default) aws_db_instance.orders (resource_id) reports-db eu-west-1 rds ./shared-infra (prod) aws_db_instance.reports (resource_id) web-alb eu-west-1 alb ./app-infra (default) aws_lb.web (arn) 1 not covered billing-cluster-1 eu-west-1 rds member of an Aurora or Multi-AZ DB cluster Import candidates need a configuration review and a terraform plan before applying. Use --format json for full details (ARNs, resource and import IDs, tags).
oos checks so far.One account. Several Terraform projects. One clear report.
Point oos at your AWS profile and your Terraform working directories. It checks the supported resources against every state you supply and brings the gaps to the top.
Tracked resources link back to their Terraform address. Incomplete checks are clearly marked, so a state that could not be read never shows up as “unmanaged”.
Read-only
Lists resources through the AWS API and reads state with terraform state pull. It never runs plan or apply, and never changes AWS resources or Terraform state.
Careful with state
Terraform state holds secrets. oos keeps only the identifiers it needs and never prints raw state or Terraform’s own error output.
Matches on real identity
Where AWS gives a resource a lasting identity, such as an RDS resource ID or a load balancer ARN, a resource recreated under the same name is not mistaken for the one in your state. Weaker matches are marked.
Give your coding agent a head start.
oos handles AWS discovery and Terraform state matching before your agent gets involved. Export the report as JSON, then ask your agent to investigate the findings and help prepare Terraform changes.
oos --profile default \
--source ./app-infra \
--source ./shared-infra \
--format json \
--output outofstate.json
Your agent starts with resource identities, import IDs, matching evidence and coverage details. You choose what to investigate and how to resolve it.
The repository includes an agent skill that teaches Claude Code, and other agents that read the Agent Skills format, to run oos, write import blocks and stop at a plan for you to review. It never applies changes. In Claude Code:
/plugin marketplace add gordonmurray/outofstate.dev
/plugin install oos@outofstate
Start with the infrastructure you already have.
Works with Terraform and OpenTofu (--tf-binary tofu), and runs on your machine with your existing AWS and state-backend access. Each source must be a working directory where init has already been run.
RDS DB instances
Matched on the immutable resource ID against aws_db_instance. Older state without one falls back to ARN or name, marked as a weaker match.
Application and Network Load Balancers
Matched on the load balancer ARN against aws_lb and aws_alb.
S3 general purpose buckets
Matched on bucket name against aws_s3_bucket, and on region when the state records it. Buckets have no lasting ID, so one recreated with the same name in the same region looks the same.
More resource types are on the way. When a resource’s tags show that CloudFormation, Elastic Beanstalk or Kubernetes manages it (or an S3 bucket’s name follows such a tool’s convention), the report adds a warning so you check there before importing.
Install in one line.
For Linux and macOS, on Intel and ARM (including Apple Silicon). The installer checks the download against its SHA-256 checksum before installing oos into ~/.local/bin.
curl -fsSL https://outofstate.dev/install.sh | bash
Then run it from a Terraform working directory:
oos --profile default
Releases come with signed build provenance you can verify with the GitHub CLI. See the README for options, the IAM permissions it needs, and how to read the report.