Out of State

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).
Example output. Two resources need a look, three are tracked with the state and address that manage them, and one is outside what 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

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.

lb

Application and Network Load Balancers

Matched on the load balancer ARN against aws_lb and aws_alb.

s3

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.