15 Prompts for Terraform and Infrastructure as Code: From Modules to Multi-Cloud

Infrastructure as Code (IaC) has transformed how teams manage cloud resources. With Terraform at the forefront, engineers can define, provision, and version infrastructure with declarative configuration. However, even experienced practitioners hit walls—module design, state management, multi-cloud orchestration—that require more than just a terraform apply. This collection of 15 carefully crafted prompts helps you leverage AI assistants (like ChatGPT or Claude) to streamline Terraform workflows. Each prompt is framed as a real-world scenario with a problem, a solution prompt, an example result, and key takeaways. Whether you're new to IaC or managing multi-cloud deployments, these prompts will sharpen your infrastructure automation skills.


🧩 Basic Prompts: Getting Started with Terraform

1. Structuring Your First Terraform Project

Problem – You're new to Terraform and unsure how to organize files, providers, and variables. A flat directory with one main.tf quickly becomes unmanageable.

Prompt

"I am creating my first Terraform project for AWS. Provide a recommended folder structure that separates variables, outputs, and configurations. Include a sample main.tf that deploys an S3 bucket with versioning, and a variables.tf file with proper type constraints and descriptions. Explain the role of each file."

Example Result

project/
├── main.tf
├── variables.tf
├── outputs.tf
├── terraform.tfvars
└── versions.tf

In main.tf:

provider "aws" {
  region = var.aws_region
}

resource "aws_s3_bucket" "example" {
  bucket = var.bucket_name
  acl    = "private"

  versioning {
    enabled = true
  }
}

Explanation – This structure follows HashiCorp's best practices by separating concerns. variables.tf defines inputs; outputs.tf exposes attributes; versions.tf pins provider versions. The prompt yields a clean template you can expand.


2. Writing Reusable Variables with Validation

Problem – Your code uses generic string variables leading to runtime errors from invalid inputs (e.g., wrong region format).

Prompt

"Show me how to add validation rules to Terraform variables for an AWS region, an instance type, and a CIDR block. Include error messages that help users fix mistakes. Use validation blocks and describe how they work."

Example Result

variable "aws_region" {
  description = "AWS region, e.g., us-east-1"
  type        = string
  validation {
    condition     = can(regex("^[a-z]{2}-[a-z]+-[0-9]{1}$", var.aws_region))
    error_message = "Region must match pattern like us-east-1 or eu-west-2."
  }
}

Explanation – Validation blocks run during plan and validate, catching issues early. This prompt teaches pattern matching and custom error messages, reducing misconfigurations.


3. Using terraform plan to Review Changes Safely

Problem – You're about to modify a production resource but aren't sure what Terraform will change. You need a process to audit plans without applying.

Prompt

"Explain how to safely run terraform plan and save the output for review. Provide a command sequence that writes the plan to a file, shows a human-readable summary, and applies only after manual approval. Include how to use terraform show to visualize the plan."

Example Result

terraform plan -out=tfplan
terraform show tfplan
tfplan | head -50   # inspect first lines
terraform apply tfplan

Explanation – The -out flag saves the plan; terraform show prints it. This workflow is standard for CI/CD—HashiCorp's Run Task documentation reinforces this pattern.


4. Managing Dependencies Between Resources

Problem – Your configuration fails because an EC2 instance depends on a security group, but Terraform doesn't always infer the order correctly.

Prompt

"I have an AWS EC2 instance that needs to reference a security group created in the same configuration. Show how to use implicit and explicit dependencies in Terraform. Give an example with depends_on and explain when it's necessary."

Example Result

resource "aws_security_group" "web_sg" {
  name        = "web-sg"
  description = "Allow HTTP"
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_instance" "web" {
  ami                    = "ami-0c55b159cbfafe1f0"
  vpc_security_group_ids = [aws_security_group.web_sg.id]  # implicit dependency
}

Explanation – Implicit dependencies use attribute references (aws_security_group.web_sg.id). Explicit depends_on is needed for dependencies Terraform can't detect, such as when using null_resource. This prompt clarifies the concept.


5. Working with Terraform State Files

Problem – You lost your local terraform.tfstate and can't manage existing resources. You need a strategy to handle state recovery and remote storage.

Prompt

"I accidentally deleted my local terraform state file. How do I recover it from an S3 backend if I configured remote state? Also explain how to migrate from local to remote state with a step-by-step guide and code for an S3 backend with DynamoDB locking."

Example Result

terraform {
  backend "s3" {
    bucket         = "my-terraform-state-bucket"
    key            = "prod/terraform.tfstate"
    region         = "us-east-1"
    dynamodb_table = "terraform-locks"
    encrypt        = true
  }
}

After adding the backend block, run terraform init -migrate-state to copy local state to S3. If the local file is missing, fetch it with aws s3 cp s3://bucket/prod/terraform.tfstate ..

Explanation – Remote state with locking prevents corruption and enables team collaboration. The DynamoDB table ensures only one person runs apply at a time. This prompt references Terraform's backend docs.


⚙️ Advanced Prompts: Modules, Workspaces, and Remote Operations

6. Designing a Reusable Terraform Module

Problem – You're deploying the same pattern (VPC + subnets + bastion host) across multiple environments. Copying and pasting leads to drift and maintenance nightmares.

Prompt

"Create a Terraform module for an AWS VPC with public and private subnets, and a bastion host. The module should accept variables for cidr_block, environment name, and number of availability zones. Include outputs for vpc_id, subnet_ids, and bastion public IP. Provide example usage from a root module."

Example Result

# module/vpc-bastion/main.tf
resource "aws_vpc" "main" {
  cidr_block = var.cidr_block
  tags = { Name = "${var.env}-vpc" }
}

resource "aws_subnet" "public" {
  count             = var.az_count
  vpc_id            = aws_vpc.main.id
  cidr_block        = cidrsubnet(var.cidr_block, 8, count.index)
  availability_zone = data.aws_availability_zones.available.names[count.index]
}

# root/main.tf
module "network" {
  source     = "./modules/vpc-bastion"
  cidr_block = "10.0.0.0/16"
  env        = "production"
  az_count   = 3
}

Explanation – Modules encapsulate infrastructure patterns. The prompt forces you to think about input/output contracts. Terraform Registry offers many public modules you can study.


7. Using Workspaces for Environment Isolation

Problem – You have dev, staging, and prod environments. You want separate state files but reuse the same configuration.

Prompt

"Explain how to use Terraform workspaces to manage multiple environments. Show how to create workspaces, select them, and conditionally configure resources based on workspace name. Include a code snippet that uses terraform.workspace to set instance sizes."

Example Result

resource "aws_instance" "app" {
  instance_type = terraform.workspace == "prod" ? "t3.large" : "t3.micro"
  ami           = "ami-0abcdef"
  tags = {
    Environment = terraform.workspace
  }
}

Commands: terraform workspace new prod, terraform workspace select dev. Each workspace has its own state file (e.g., terraform.tfstate.d/dev/).

Explanation – Workspaces are lightweight but limited to a single backend; for more complex needs, use separate directories or Terragrunt. HashiCorp recommends workspaces for simple cases.


8. Generating Infrastructure Documentation Automatically

Problem – Your team doesn't know what infrastructure is deployed because documentation is out of date.

Prompt

"I need to automatically generate a Markdown documentation page that lists all resources managed by Terraform, including their type, name, and output values. Show how to use terraform output and terraform state list with a script, or recommend tools like terraform-docs. Provide a sample output."

Example Result

echo "# Infrastructure Overview" > docs/infra.md
echo "## Resources" >> docs/infra.md
terraform state list >> docs/infra.md
echo "## Outputs" >> docs/infra.md
terraform output -json | jq '.' >> docs/infra.md

Using terraform-docs auto-generates tables from variables and outputs. The prompt leads to a reproducible documentation pipeline.

Explanation – Keeping docs in sync reduces onboarding friction. The community tool terraform-docs is widely adopted and available on terraform-docs.io.


9. Troubleshooting Error Messages with terraform console

Problem – You get an error like "Error: Invalid function argument" and can't figure out the expression result.

Prompt

"Explain how to use terraform console to test expressions and function calls interactively. Provide examples of debugging a cidrsubnet calculation, checking if a variable is null, and verifying interpolation. Include the exact commands to open the console and exit."

Example Result

terraform console
> cidrsubnet("10.0.0.0/16", 8, 0)
"10.0.0.0/24"
> var.env != null ? var.env : "unknown"
"production"
> exit

Explanationterraform console evaluates expressions in the context of your configuration and state. It's an underused tool that prevents guesswork.


10. Applying Policies with Sentinel or OPA

Problem – Your team deploys resources that violate security policies (e.g., S3 buckets with public access). You need to enforce rules without manual review.

Prompt

"Write a policy in HashiCorp Sentinel (or OPA/Rego) that forbids AWS S3 buckets from having acl = "public-read" or any public access block set to false. Include how to test this policy with terraform plan. Which approach is more portable: Sentinel (Terraform Cloud) or OPA?"

Example Result (OPA/Rego)

package terraform

deny[msg] {
  resource := input.resource_changes[_]
  resource.type == "aws_s3_bucket"
  resource.change.after.acl == "public-read"
  msg = sprintf("Bucket %s must not have public ACL", [resource.address])
}

Explanation – Policy as Code prevents misconfigurations before they reach production. Reference: HashiCorp Sentinel and OPA for Terraform.


🌐 Expert Prompts: Multi-Cloud, State Refactoring, and Automation

11. Managing Multi-Cloud Resources (AWS + Azure)

Problem – Your organization uses both AWS and Azure. You need a unified way to provision VMs across clouds without duplication.

Prompt

"Design a Terraform configuration that deploys a virtual machine on AWS (EC2) and on Azure (VM) using providers conditionally. Use a variable cloud_provider that accepts 'aws' or 'azure'. Show how to manage credentials for both providers and how to structure the code to avoid mixing resources."

Example Result

variable "cloud_provider" {
  type    = string
  default = "aws"
}

provider "aws" {
  region = "us-east-1"
}

provider "azurerm" {
  features {}
}

resource "aws_instance" "vm" {
  count       = var.cloud_provider == "aws" ? 1 : 0
  ami         = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"
}

resource "azurerm_virtual_machine" "vm" {
  count                = var.cloud_provider == "azure" ? 1 : 0
  name                 = "myVM"
  location             = "East US"
  resource_group_name  = azurerm_resource_group.rg.name
  network_interface_ids = [azurerm_network_interface.nic.id]
  vm_size              = "Standard_B1s"
}

Explanation – Using count with conditions keeps the code unified. However, for complex multi-cloud, separate modules per cloud are cleaner. This prompt encourages thinking about provider configurations and conditional resource creation.


12. Refactoring State with terraform state mv

Problem – You renamed a resource or moved it to a module, and now Terraform wants to destroy and recreate it. You need to avoid downtime.

Prompt

"I have a resource aws_instance.web that I want to move into a module module.compute. Show the terraform state mv command to update the state without destroying the instance. Also explain how to handle the case where the resource address changed due to module refactoring."

Example Result

terraform state mv aws_instance.web module.compute.aws_instance.web

After moving, update the configuration to match the new address. Run terraform plan to verify zero changes.

Explanationterraform state mv is safe for moving resources within the same state. For cross-state moves (e.g., splitting a state), use terraform state rm and terraform import. This technique is critical for evolving infrastructure.


13. Automating Terraform with GitHub Actions

Problem – You want a CI/CD pipeline that runs terraform plan on every pull request and applies automatically after merge.

Prompt

"Create a GitHub Actions workflow that runs terraform fmt, terraform init, and terraform plan on every PR, and applies changes when the PR is merged to main. Include OIDC authentication to AWS to avoid hardcoded credentials. The workflow should use hashicorp/setup-terraform action."

Example Result

name: "Terraform CI"
on: [pull_request, push]
jobs:
  terraform:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-terraform@v2
        with:
          terraform_version: 1.6.0
      - name: fmt
        run: terraform fmt -check
      - name: init
        run: terraform init
      - name: plan
        run: terraform plan

For apply, add a condition if: github.ref == 'refs/heads/main' && github.event_name == 'push'.

Explanation – OIDC eliminates storing AWS keys. Many teams adopt this pattern; see HashiCorp's guide.


14. Using terraform import for Existing Resources

Problem – You have manually created resources (e.g., a VPC) and want to bring them under Terraform management without recreation.

Prompt

"I have an existing AWS S3 bucket named my-existing-bucket that was created outside Terraform. Walk me through writing the configuration block for aws_s3_bucket and then using terraform import to import it. Include how to verify the import with terraform plan and what to do if there are configuration differences."

Example Result

resource "aws_s3_bucket" "imported" {
  bucket = "my-existing-bucket"
  acl    = "private"  # depends on actual settings
}
terraform import aws_s3_bucket.imported my-existing-bucket
terraform plan
# if differences appear, adjust configuration to match reality

Explanationterraform import is powerful but requires you to write the resource block first. Tools like terraformer can automate this for large inventories.


15. Tainting and Untainting Resources for Controlled Recreation

Problem – A specific resource is misconfigured (e.g., a security group rule) and you need to recreate it without affecting dependencies.

Prompt

"Explain the terraform taint and terraform untaint commands. When should you use them instead of manual destroy? Provide examples of tainting an AWS EC2 instance and a module resource. Note that in Terraform 1.5+, the preferred method is -replace flag; include both approaches."

Example Result

# Legacy approach
export TF_CLI_ARGS_plan="-generate-config-out=generated.tf"
terraform taint aws_instance.web
terraform apply -replace="aws_instance.web"

# Modern approach (v1.5+)
terraform apply -replace="aws_instance.web"

Explanation-replace is cleaner because it doesn't modify state permanently. The prompt highlights the evolution of Terraform best practices.


🏁 Conclusion

These 15 prompts cover the full spectrum of Terraform usage—from beginner organization to expert multi-cloud and state manipulation. By integrating these prompts into your daily workflow, you can accelerate learning, reduce errors, and build more resilient infrastructure. Remember to always validate prompts with official documentation (e.g., Terraform Language Documentation). Try running one of these prompts with an AI assistant today, and watch your IaC skills grow. Happy automating!

← All posts

Comments