Introduction
Infrastructure as Code (IaC) has transformed how organizations manage cloud resources, and Terraform remains the de facto standard in 2026. Whether you are building reusable modules, troubleshooting state conflicts, or orchestrating multi-cloud deployments, crafting the right prompt can save hours of manual work. This article presents ten expert-level prompts for Terraform and IaC, organized from basic to advanced, with real-world examples and actionable outputs. Each prompt is designed to be used with AI assistants, documentation tools, or directly in your workflow. By the end, you will have a portable prompt library that accelerates your Terraform development and reduces common errors.
Why Prompts Matter for Terraform
Terraform’s declarative language is powerful, but its complexity grows with scale. A single misconfigured module can cascade into state drift, failed applies, or security gaps. Prompts act as structured instructions that guide AI tools or human collaborators to produce consistent, production-ready code. They enforce best practices, incorporate security checks, and generate documentation alongside infrastructure definitions. In multi-cloud environments, where AWS, Azure, and GCP conventions differ, well-crafted prompts ensure portability and reduce cognitive load.
Basic Prompts: Getting Started with Terraform
1. Generate a Basic AWS EC2 Instance
Task: Create a Terraform configuration that provisions an EC2 instance with a security group, using variables and outputs.
Prompt:
Write a Terraform configuration file (main.tf) that creates an AWS EC2 instance of type t3.micro in us-east-1. Include:
- A variable for instance_name with default "web-server"
- A security group allowing SSH (port 22) and HTTP (port 80) from 0.0.0.0/0
- An output showing the public IP of the instance
- Use the hashicorp/aws provider version ~> 5.0
Example Result:
# main.tf
provider "aws" {
region = "us-east-1"
}
variable "instance_name" {
description = "Name tag for the EC2 instance"
type = string
default = "web-server"
}
resource "aws_security_group" "web_sg" {
name = "web-sg"
description = "Allow SSH and HTTP"
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
security_groups = [aws_security_group.web_sg.name]
tags = {
Name = var.instance_name
}
}
output "public_ip" {
value = aws_instance.web.public_ip
}
2. Create a Reusable Module for VPC
Task: Build a modular VPC component that can be reused across projects.
Prompt:
Design a Terraform module for a VPC with the following requirements:
- Module name: "vpc-module"
- Inputs: vpc_cidr (default "10.0.0.0/16"), environment (default "dev"), public_subnet_cidrs (list of strings)
- Outputs: vpc_id, public_subnet_ids
- Create two public subnets in different availability zones
- Attach an internet gateway to the VPC
- Use count to iterate over subnet CIDRs
- Include a description for each variable and output
Example Result:
# modules/vpc-module/main.tf
variable "vpc_cidr" {
description = "CIDR block for the VPC"
type = string
default = "10.0.0.0/16"
}
variable "environment" {
description = "Deployment environment (dev, staging, prod)"
type = string
default = "dev"
}
variable "public_subnet_cidrs" {
description = "List of CIDR blocks for public subnets"
type = list(string)
}
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
tags = {
Name = "${var.environment}-vpc"
Environment = var.environment
}
}
resource "aws_internet_gateway" "gw" {
vpc_id = aws_vpc.main.id
tags = {
Name = "${var.environment}-igw"
}
}
resource "aws_subnet" "public" {
count = length(var.public_subnet_cidrs)
vpc_id = aws_vpc.main.id
cidr_block = var.public_subnet_cidrs[count.index]
availability_zone = element(data.aws_availability_zones.available.names, count.index)
map_public_ip_on_launch = true
tags = {
Name = "${var.environment}-public-subnet-${count.index + 1}"
}
}
data "aws_availability_zones" "available" {
state = "available"
}
output "vpc_id" {
description = "ID of the VPC"
value = aws_vpc.main.id
}
output "public_subnet_ids" {
description = "IDs of the public subnets"
value = aws_subnet.public[*].id
}
Intermediate Prompts: State Management and Modules
3. Configure Remote State with S3 and DynamoDB Locking
Task: Set up a remote backend for Terraform state with state locking to prevent concurrent modifications.
Prompt:
Generate Terraform code to create an S3 bucket (with versioning enabled) and a DynamoDB table for state locking. Then show how to configure the backend in root configuration. The bucket name should include a random suffix. The DynamoDB table should have a primary key "LockID" of type String. Use the random provider to generate a unique bucket name.
Example Result:
# backend-setup.tf
provider "aws" {
region = "us-west-2"
}
resource "random_id" "bucket_suffix" {
byte_length = 8
}
resource "aws_s3_bucket" "terraform_state" {
bucket = "terraform-state-${random_id.bucket_suffix.hex}"
versioning {
enabled = true
}
server_side_encryption_configuration {
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
tags = {
Name = "Terraform State Bucket"
}
}
resource "aws_dynamodb_table" "terraform_locks" {
name = "terraform-locks"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
tags = {
Name = "Terraform Lock Table"
}
}
output "state_bucket" {
value = aws_s3_bucket.terraform_state.bucket
}
output "lock_table" {
value = aws_dynamodb_table.terraform_locks.name
}
Root backend configuration:
# backend.tf (in root module)
terraform {
backend "s3" {
bucket = "terraform-state-<actual-suffix>"
key = "global/s3/terraform.tfstate"
region = "us-west-2"
dynamodb_table = "terraform-locks"
encrypt = true
}
}
4. Refactor a Monolithic Terraform Configuration into Modules
Task: Take a flat configuration with multiple resources and split it into reusable modules.
Prompt:
Given the following monolithic Terraform code that creates an EC2 instance, an RDS database, and an S3 bucket, rewrite it into three separate modules: ec2-module, rds-module, s3-module. Each module should have its own variables.tf and outputs.tf. The root main.tf should call these modules with appropriate inputs. Include a module for networking (vpc) that is shared.
Example Result (Root main.tf):
# main.tf
provider "aws" {
region = var.region
}
module "vpc" {
source = "./modules/vpc"
vpc_cidr = "10.0.0.0/16"
environment = var.environment
public_subnet_cidrs = ["10.0.1.0/24", "10.0.2.0/24"]
}
module "ec2" {
source = "./modules/ec2"
instance_type = var.instance_type
subnet_id = module.vpc.public_subnet_ids[0]
environment = var.environment
}
module "rds" {
source = "./modules/rds"
db_name = var.db_name
db_username = var.db_username
db_password = var.db_password
subnet_ids = module.vpc.public_subnet_ids
environment = var.environment
}
module "s3" {
source = "./modules/s3"
bucket_name = var.bucket_name
environment = var.environment
}
Advanced Prompts: Multi-Cloud and Complex Scenarios
5. Deploy a Multi-Cloud Application Across AWS and Azure
Task: Create a Terraform configuration that provisions a virtual machine on AWS (EC2) and a virtual machine on Azure (VM), connected via a VPN tunnel.
Prompt:
Write a multi-cloud Terraform configuration using the hashicorp/aws and hashicorp/azurerm providers. Deploy:
- AWS: one EC2 instance (t3.micro) with a public IP in us-east-1
- Azure: one VM (Standard_B1s) with a public IP in East US
- Use a module for each cloud provider
- Output the public IPs of both instances
- Do not implement the VPN tunnel (just stub the resources)
Example Result:
# main.tf
provider "aws" {
region = "us-east-1"
}
provider "azurerm" {
features {}
}
module "aws_vm" {
source = "./modules/aws-vm"
instance_type = "t3.micro"
ami_id = "ami-0c55b159cbfafe1f0"
subnet_id = module.vpc.public_subnet_ids[0]
}
module "azure_vm" {
source = "./modules/azure-vm"
vm_size = "Standard_B1s"
location = "eastus"
admin_username = "adminuser"
}
output "aws_public_ip" {
value = module.aws_vm.public_ip
}
output "azure_public_ip" {
value = module.azure_vm.public_ip
}
6. Manage Terraform State with Workspaces for Multi-Environment
Task: Use Terraform workspaces to manage separate state files for dev, staging, and prod environments.
Prompt:
Show how to configure Terraform workspaces for three environments (dev, staging, prod). The configuration should use a local backend but with different state files per workspace. Include a variables file that sets instance_type based on workspace: dev=t3.nano, staging=t3.micro, prod=t3.small. Also show commands to create and switch workspaces.
Example Result:
# variables.tf
variable "instance_type" {
description = "EC2 instance type based on environment"
type = string
}
# terraform.tfvars (not used directly; workspace-specific)
# Use a map in main.tf:
locals {
instance_type_map = {
dev = "t3.nano"
staging = "t3.micro"
prod = "t3.small"
}
}
resource "aws_instance" "app" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = local.instance_type_map[terraform.workspace]
tags = {
Name = "app-${terraform.workspace}"
Environment = terraform.workspace
}
}
Commands:
terraform workspace new dev
terraform workspace new staging
terraform workspace new prod
terraform workspace select dev
terraform apply -auto-approve
7. Implement a Sentinel Policy for Compliance
Task: Write a Sentinel policy that prevents EC2 instances from being deployed without encryption at rest.
Prompt:
Create a Sentinel policy file (ec2-encryption.sentinel) that enforces: all EC2 instances must have root_block_device with encrypted = true. The policy should apply to all resources of type aws_instance. Show how to attach this policy to a Terraform Cloud workspace.
Example Result:
# ec2-encryption.sentinel
import "tfplan"
# Get all EC2 instances in the plan
instances = tfplan.resource_changes["aws_instance"] ?? []
# Rule: all instances must have encrypted root block device
main = rule {
all instances as _, instance {
instance.applied.root_block_device.encrypted else false
}
}
8. Use Terragrunt to Manage Multiple Terraform Modules
Task: Demonstrate how Terragrunt can be used to keep Terraform configurations DRY by defining remote state and provider configurations once.
Prompt:
Write a Terragrunt configuration that defines a remote state block in root.hcl and then uses it in two child modules (vpc and ec2). The root.hcl should configure S3 backend with DynamoDB locking. Show the directory structure.
Example Result:
# terragrunt.hcl (root)
remote_state {
backend = "s3"
config = {
bucket = "my-terraform-state"
key = "${path_relative_to_include()}/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
# dev/terragrunt.hcl
include {
path = find_in_parent_folders()
}
# dev/vpc/terragrunt.hcl
include {
path = find_in_parent_folders()
}
generate "provider" {
path = "provider.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
provider "aws" {
region = "us-east-1"
}
EOF
}
Expert Prompts: Optimization and Debugging
9. Debug a Terraform State Conflict
Task: Resolve a state lock error when multiple team members run terraform apply simultaneously.
Prompt:
Explain step-by-step how to diagnose and resolve a Terraform state lock error caused by a stale lock in DynamoDB. Provide the AWS CLI command to check the lock, force unlock if safe, and preventive measures using pre-commit hooks or CI pipelines.
Example Result:
# Check current lock
aws dynamodb get-item --table-name terraform-locks --key '{"LockID": {"S": "my-bucket/global/s3/terraform.tfstate-md5"}}'
# Force unlock (only after confirming no active process)
terraform force-unlock <LOCK_ID>
# Preventive: use CI pipeline with sequential stages
# In GitHub Actions, use concurrency group:
concurrency:
group: terraform-${{ github.ref }}
cancel-in-progress: false
10. Optimize Terraform Plan Time for Large Infrastructure
Task: Reduce terraform plan execution time for a deployment with hundreds of resources by using targeted plans and state filtering.
Prompt:
Provide strategies to speed up Terraform plan for large deployments (100+ resources). Include: using -target for specific resources, splitting state into multiple workspaces, using terraform_remote_state data sources, and leveraging refresh=false in CI. Give concrete examples of -target usage and a script to identify long-running resources.
Example Result:
# Plan only a specific module
export TF_WORKSPACE=prod
export TF_LOG=WARN
time terraform plan -target=module.vpc -target=module.ec2
# Skip refresh in CI
export TF_IN_AUTOMATION=true
terraform plan -refresh=false
# Use terraform_remote_state instead of data sources where possible
# In module:
data "terraform_remote_state" "network" {
backend = "s3"
config = {
bucket = "shared-state"
key = "network/terraform.tfstate"
region = "us-east-1"
}
}
Practical Use Cases in 2026
Many organizations now combine Terraform with policy-as-code tools like Sentinel or OPA to enforce compliance before deployment. For example, a financial services company might use the Sentinel policy from Prompt 7 to ensure all EC2 instances have encrypted volumes, reducing audit failures. Another common pattern is using Terragrunt (Prompt 8) to manage state across hundreds of microservices, where each service gets its own state file but shares provider and backend configuration.
Conclusion
These ten prompts cover the essential spectrum of Terraform and IaC work—from basic resource creation to advanced multi-cloud orchestration and debugging. By adapting them to your specific cloud providers and organizational policies, you can standardize infrastructure patterns, reduce errors, and accelerate deployments. The key is to treat prompts as living documentation: update them as providers evolve, and share them within your team to enforce best practices. Start with the basic prompts to build confidence, then tackle the advanced ones as your infrastructure grows. With the right prompts, Terraform becomes not just a tool, but a disciplined practice.
This article was written for asibiont.com/blog. For more expert guides on IaC and cloud engineering, explore our course library.
Comments