Terraform Search Import
HashiCorpOfficialPublished by HashiCorp
- Skill
- Workflow
- Cloud and DevOps
- MPL-2.0
- Low risk
- Has scripts
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a structured approach to bringing unmanaged cloud infrastructure under Terraform control. It leverages Terraform Search capabilities to query existing resources and generate the necessary configuration and import blocks. The process includes verifying provider support, defining search criteria in .tfquery.hcl files, generating resource configurations, and refining the output for production use. It also includes a fallback manual discovery workflow for resources not yet supported by the search feature.
What it does
- Verifies provider support for list-based resource discovery.
- Defines declarative search queries for cloud resources using .tfquery.hcl files.
- Generates Terraform resource and import blocks automatically.
- Supports filtering and multi-region resource discovery.
- Provides a manual import workflow for unsupported resource types.
- Guides users through the post-generation cleanup of imported configuration.
When to use it
- When migrating existing manual cloud infrastructure to Infrastructure as Code.
- When auditing cloud resources across multiple accounts or regions.
- When bringing unmanaged resources under Terraform state management.
- When you need to bulk import resources rather than importing them one by one.
Advantages
- Reduces manual effort by automating the generation of import configuration.
- Ensures consistency by using declarative queries for resource discovery.
- Provides a clear decision path between automated search and manual import methods.
- Includes validation steps to ensure provider compatibility before execution.
Usage examples
- “How do I find all my production EC2 instances to import them into Terraform?”
- The agent will guide you to create a .tfquery.hcl file with a list block filtering by the 'Environment' tag set to 'production', then run 'terraform query' to generate the import configuration.
- “I need to import existing DynamoDB tables, but they don't appear in the search results.”
- The agent will direct you to the manual discovery workflow, providing examples on how to use the AWS CLI to list tables and manually construct the required resource and import blocks.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/hashicorp/terraform-search-import/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip terraform-search-import.zip -d .agents/skills
Documentation by HashiCorp
Terraform Search and Bulk Import
Discover existing cloud resources using declarative queries and generate configuration for bulk import into Terraform state.
References:
When to Use
Bringing unmanaged resources under Terraform control
Auditing existing cloud infrastructure
Migrating from manual provisioning to IaC
Discovering resources across multiple regions/accounts
IMPORTANT: Check Provider Support First
BEFORE starting, you MUST verify the target resource type is supported:
# Check what list resources are available
./scripts/list_resources.sh aws # Specific provider
./scripts/list_resources.sh # All configured providersDecision Tree
Identify target resource type (e.g., aws_s3_bucket, aws_instance)
Check if supported: Run
./scripts/list_resources.sh <provider>Choose workflow:
** If supported**: Check for terraform version available.
** If terraform version is above 1.14.0** Use Terraform Search workflow (below)
** If not supported or terraform version is below 1.14.0 **: Use Manual Discovery workflow (see references/MANUAL-IMPORT.md)
Note: The list of supported resources is rapidly expanding. Always verify current support before using manual import.
Prerequisites
Before writing queries, verify the provider supports list resources for your target resource type.
Discover Available List Resources
Run the helper script to extract supported list resources from your provider:
# From a directory with provider configuration (runs terraform init if needed)
./scripts/list_resources.sh aws # Specific provider
./scripts/list_resources.sh # All configured providersOr manually query the provider schema:
terraform providers schema -json | jq '.provider_schemas | to_entries | map({key: (.key | split("/")[-1]), value: (.value.list_resource_schemas // {} | keys)})'Terraform Search requires an initialized working directory. Ensure you have a configuration with the required provider before running queries:
# terraform.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
}
}Run terraform init to download the provider, then proceed with queries.
Terraform Search Workflow (Supported Resources Only)
Create
.tfquery.hclfiles withlistblocks defining search queriesRun
terraform queryto discover matching resourcesGenerate configuration with
-generate-config-out=<file>Review and refine generated
resourceandimportblocksRun
terraform planandterraform applyto import
Query File Structure
Query files use .tfquery.hcl extension and support:
providerblocks for authenticationlistblocks for resource discoveryvariableandlocalsblocks for parameterization
# discovery.tfquery.hcl
provider "aws" {
region = "us-west-2"
}
list "aws_instance" "all" {
provider = aws
}List Block Syntax
list "<list_type>" "<symbolic_name>" {
provider = <provider_reference> # Required
# Optional: filter configuration (provider-specific)
# The `config` block schema is provider-specific. Discover available options using `terraform providers schema -json | jq '.provider_schemas."registry.terraform.io/hashicorp/<provider>".list_resource_schemas."<resource_type>"'`
config {
filter {
name = "<filter_name>"
values = ["<value1>", "<value2>"]
}
region = "<region>" # AWS-specific
}
# Optional: limit results
limit = 100
}Supported List Resources
Provider support for list resources varies by version. Always check what's available for your specific provider version using the discovery script.
Query Examples
Basic Discovery
# Find all EC2 instances in configured region
list "aws_instance" "all" {
provider = aws
}Filtered Discovery
# Find instances by tag
list "aws_instance" "production" {
provider = aws
config {
filter {
name = "tag:Environment"
values = ["production"]
}
}
}
# Find instances by type
list "aws_instance" "large" {
provider = aws
config {
filter {
name = "instance-type"
values = ["t3.large", "t3.xlarge"]
}
}
}Multi-Region Discovery
provider "aws" {
region = "us-west-2"
}
locals {
regions = ["us-west-2", "us-east-1", "eu-west-1"]
}
list "aws_instance" "all_regions" {
for_each = toset(local.regions)
provider = aws
config {
region = each.value
}
}Parameterized Queries
variable "target_environment" {
type = string
default = "staging"
}
list "aws_instance" "by_env" {
provider = aws
config {
filter {
name = "tag:Environment"
values = [var.target_environment]
}
}
}Running Queries
# Execute queries and display results
terraform query
# Generate configuration file
terraform query -generate-config-out=imported.tf
# Pass variables
terraform query -var='target_environment=production'Query Output Format
list.aws_instance.all account_id=123456789012,id=i-0abc123,region=us-west-2 web-serverColumns: <query_address> <identity_attributes> <name_tag>
Generated Configuration
The -generate-config-out flag creates:
# __generated__ by Terraform
resource "aws_instance" "all_0" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
# ... all attributes
}
import {
to = aws_instance.all_0
provider = aws
identity = {
account_id = "123456789012"
id = "i-0abc123"
region = "us-west-2"
}
}Post-Generation Cleanup
Generated configuration includes all attributes. Clean up by:
Remove computed/read-only attributes
Replace hardcoded values with variables
Add proper resource naming
Organize into appropriate files
# Before: generated
resource "aws_instance" "all_0" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
arn = "arn:aws:ec2:..." # Remove - computed
id = "i-0abc123" # Remove - computed
# ... many more attributes
}
# After: cleaned
resource "aws_instance" "web_server" {
ami = var.ami_id
instance_type = var.instance_type
subnet_id = var.subnet_id
tags = {
Name = "web-server"
Environment = var.environment
}
}Import by Identity
Generated imports use identity-based import (Terraform 1.12+):
import {
to = aws_instance.web
provider = aws
identity = {
account_id = "123456789012"
id = "i-0abc123"
region = "us-west-2"
}
}Verifying Imported State
After running terraform apply to import resources, verify what actually landed in state.
Prefer the documented, stable, and more token-efficient commands over reading the raw state
file:
# Confirm resources are now managed (also confirms addresses)
terraform state list
# Inspect resolved attribute values for imported resources
terraform show -json | jq '.values.root_module.resources[] | {address, type, name}'terraform show -json requires providers to be installed (terraform init), since it
renders values against provider schemas. Fall back to the raw state
(terraform state pull / terraform.tfstate) only when providers aren't available and
init can't run, you need only coarse info (addresses, outputs, serial/lineage), or you
must avoid executing Terraform. Avoid parsing the raw version-4 state format as a stable
interface. Note: state contains sensitive values in plaintext in every format — never
echo state contents into logs or output.
Best Practices
Query Design
Start broad, then add filters to narrow results
Use
limitto prevent overwhelming outputTest queries before generating configuration
Configuration Management
Review all generated code before applying
Remove unnecessary default values
Use consistent naming conventions
Add proper variable abstraction
Troubleshooting
| Issue | Solution |
|---|---|
| "No list resources found" | Check provider version supports list resources |
| Query returns empty | Verify region and filter values |
| Generated config has errors | Remove computed attributes, fix deprecated arguments |
| Import fails | Ensure resource not already in state |
Complete Example
# main.tf - Initialize provider
terraform {
required_version = ">= 1.14"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0" # Always use latest version
}
}
}
# discovery.tfquery.hcl - Define queries
provider "aws" {
region = "us-west-2"
}
list "aws_instance" "team_instances" {
provider = aws
config {
filter {
name = "tag:Owner"
values = ["platform"]
}
filter {
name = "instance-state-name"
values = ["running"]
}
}
limit = 50
}# Execute workflow
terraform init
terraform query
terraform query -generate-config-out=generated.tf
# Review and clean generated.tf
terraform plan
terraform applyFiles
- ATTRIBUTION.mdAdded by AutoGineer914 B
- LICENSELicence file added by AutoGineer16.3 KiB
- SKILL.md9.7 KiB
- references/MANUAL-IMPORT.md2.4 KiB
- scripts/list_resources.shScript1.2 KiB
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs a command-line tool
Security
What our scanner noticed· Low risk
- Scripts that your agent may run
This skill includes scripts that your agent may run. Read them before you use it.
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Published by
- HashiCorp
- Publisher
- HashiCorp (Official)
- Source
- hashicorp/agent-skills · plugins/terraform/skills/terraform-search-import · commit 5e30fa5
- Licence
- Mozilla Public License 2.0 (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by HashiCorp.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download terraform-search-import.zip