terraform 66 Q&As

Terraform FAQ & Answers

66 expert Terraform answers researched from official documentation. Every answer cites authoritative sources you can verify.

unknown

66 questions
A

Terraform is HashiCorp's declarative infrastructure as code (IaC) tool that enables safe, efficient infrastructure provisioning across 5,710+ providers (2025). Current version: Terraform 1.13.5 (latest stable GA), 1.14.0 in RC. Unlike imperative tools, Terraform uses a declarative approach where you describe desired end state in HCL (HashiCorp Configuration Language), and Terraform determines execution path. Core workflow: write .tf configuration → terraform init (download providers) → terraform plan (preview changes) → terraform apply (execute). Terraform maintains JSON state file tracking real-world resources, enabling change detection, dependency resolution, and drift prevention. Multi-cloud support: AWS, Azure, GCP, Kubernetes, Docker, GitHub via unified CLI. Industry standard for IaC with 5+ billion provider downloads (AWS provider v6.21.0 latest, November 2025).

99% confidence
A

Terraform 1.13.5 stable (1.14.0 RC) provides essential features for modern infrastructure automation (2025): (1) Declarative HCL syntax for human-readable configuration with IDE support, (2) Execution plans (terraform plan) preview changes before applying with cost estimation in HCP Terraform, (3) Resource dependency graph for automatic ordering and parallel execution, (4) State management tracking infrastructure with remote backends (S3, Azure Storage, GCS), (5) Multi-cloud support across 5,710+ providers. Advanced features: Workspaces for environment isolation, modules from Terraform Registry (20,956+ modules), data sources for querying existing infrastructure, lifecycle meta-arguments (create_before_destroy, prevent_destroy), built-in testing framework (terraform test in v1.6+, mocking in v1.7+), ephemeral values for secrets (v1.10+), import blocks with automatic code generation (v1.5+), native S3 state locking without DynamoDB (v1.10+). Benefits: Infrastructure versioning via Git, reproducible deployments, team collaboration, automated compliance.

99% confidence
A

HCL (HashiCorp Configuration Language) is Terraform's declarative, human-readable language for infrastructure definition. HCL2 (introduced Terraform 0.12+, current standard in 2025) adds type handling, expressions, for_each, and dynamic blocks. Basic structure: resource blocks (resource "aws_instance" "web" { ami = "ami-123" }), data sources, variables, outputs, providers. Syntax: Blocks with arguments and nested blocks. Comments: # or //. Standard file structure (2025 best practice): main.tf (core resources), variables.tf (input declarations), outputs.tf (output values), versions.tf (Terraform and provider version constraints), providers.tf (provider configuration). Declarative nature means order of blocks/files is generally insignificant - Terraform builds dependency graph automatically. HCL files use .tf extension, must be valid UTF-8 encoded. Advanced features: Conditionals (condition ? true_val : false_val), for expressions, functions (cidrsubnet, merge, lookup).

99% confidence
A

Providers are plugins that manage resource lifecycle by interacting with cloud platform/service APIs. Terraform Registry hosts 5,710+ providers (2025), with top 20 providers accounting for 85% of downloads. Configure in versions.tf:

terraform {
  required_providers {
    aws = { source = "hashicorp/aws", version = "~> 6.0" }  # 2025: v6.21.0 latest
    azurerm = { source = "hashicorp/azurerm", version = "~> 3.0" }
  }
}
provider "aws" { region = "us-east-1" }

Providers handle: Authentication (credentials), API calls (CRUD operations), schema validation, state updates. Multiple instances via aliases for multi-region: provider "aws" { alias = "us-west", region = "us-west-2" }. Lock file .terraform.lock.hcl pins exact versions. Install via terraform init. Major providers (2025): AWS (5B+ downloads, v6.21.0), Azure (azurerm), GCP, Kubernetes, Docker. Provider support for ephemeral resources (v1.10+): AWS, Azure, Kubernetes, random.

99% confidence
A

Core workflow commands (Terraform 1.10+): (1) terraform init - Initialize directory, download providers from registry, configure backend. Safe to re-run. (2) terraform validate - Check configuration syntax and consistency without accessing remote state. (3) terraform plan - Preview changes, show execution plan comparing current state to desired config. Use -out=plan.tfplan to save plan. (4) terraform apply - Execute changes, prompts for confirmation (use -auto-approve in CI/CD). (5) terraform destroy - Remove all managed resources. Additional commands: terraform fmt (format HCL to canonical style), terraform output (display output values), terraform show (inspect state/plan), terraform test (run tests, v1.6+), terraform import (import existing resources). Best practice workflow: write HCL → init → validate → plan → apply → test. Always run plan before apply in production.

99% confidence
A

Terraform state is a JSON file (terraform.tfstate) that maps HCL configuration to real-world infrastructure resources, serving as Terraform's source of truth. State contains: resource IDs (e.g., i-1234567890abcdef0), computed attributes (public IPs, DNS names), resource metadata, dependency graphs, provider configuration. State enables: (1) Change detection - Terraform compares desired config to current state during terraform plan, (2) Performance optimization - Avoids querying every resource on each run, (3) Dependency tracking - Ensures resources destroyed in correct order. State format: Human-readable JSON but NEVER manually edit (use terraform state commands instead). Critical: State contains sensitive data (passwords, keys) in plaintext - always encrypt and restrict access. Without state, Terraform cannot determine what infrastructure exists or what changes to make. Default: Local file (terraform.tfstate), production: Remote backend (S3, Azure Storage, HCP Terraform).

99% confidence
A

State management is critical for infrastructure safety and team collaboration (2025 best practices): (1) Change detection - Enables terraform plan to show precise diffs between desired vs actual infrastructure, (2) Dependency resolution - Tracks resource relationships ensuring correct creation/destruction order (destroy VMs before VPC), (3) Performance - Cached metadata avoids querying all cloud resources on every run, (4) Team collaboration - Remote state with locking prevents concurrent modifications that corrupt infrastructure, (5) Security - State contains sensitive data (passwords, private keys) requiring encryption at rest (AES-256) and in transit (TLS), (6) Blast radius control - Split state by environment/component to limit impact of errors. Poor state management causes: Configuration drift (manual changes untracked), resource conflicts (duplicate resources), infrastructure corruption (lost state = lost infrastructure tracking). Production requirements (2025): Remote backend (S3, Azure Storage, HCP Terraform), state locking enabled, encryption enabled, version control for configs (NOT state files), state splitting by environment.

99% confidence
A

Backends determine state storage location and operation execution. Types: local (default, terraform.tfstate in working directory), remote (S3, Azure Storage, GCS, HCP Terraform). BREAKING CHANGE (Terraform 1.10+, 2025): S3 now supports native state locking without DynamoDB. Configure in backend.tf:

terraform {
  backend "s3" {
    bucket         = "my-terraform-state"
    key            = "production/terraform.tfstate"
    region         = "us-east-1"
    encrypt        = true
    use_lockfile   = true  # NEW: Native S3 locking, no DynamoDB needed
  }
}

S3 creates .tflock file alongside state for locking. Legacy DynamoDB locking deprecated, will be removed in future versions. Initialize: terraform init. Migrate backends: terraform init -migrate-state. Important: Backend config cannot use variables (must be static values or use -backend-config flag). Production: Always enable versioning on S3 bucket for state recovery.

99% confidence
A

Remote state management provides critical benefits for team-based infrastructure (2025 best practices): (1) Team collaboration - Shared access via S3/Azure Storage enables multiple engineers to work simultaneously, (2) State locking - Prevents concurrent modifications that corrupt infrastructure (automatic with S3 native locking in Terraform 1.10+), (3) Encryption - AES-256 encryption at rest protects sensitive data (passwords, keys), (4) Versioning - S3 versioning enables rollback after accidental corruption, (5) Durability - 99.999999999% (11 nines) durability with S3 Standard vs risky local files, (6) CI/CD integration - Automated pipelines access shared state without local dependency, (7) Audit logging - CloudTrail/Azure Monitor tracks all state access for compliance, (8) Consistency checking - Backend validates state integrity. Popular backends (2025): S3 with native locking (no DynamoDB), Azure Blob Storage, GCS, HCP Terraform. Remote state mandatory for production - eliminates single points of failure from local state files.

99% confidence
A

Modules are reusable Terraform configurations that create organization, reduce duplication, and standardize infrastructure. Terraform Registry hosts 20,956+ modules (2025). Module structure: Directory with .tf files. Call modules:

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"  # Registry module
  version = "5.0.0"  # Always pin version
  cidr    = "10.0.0.0/16"  # Input variable
}
# Local module
module "app" {
  source = "./modules/application"
  env    = "production"
}

Inputs: variable blocks, outputs: output blocks expose values to parent. Module sources: Local path (./modules/vpc), Terraform Registry (terraform-aws-modules/vpc/aws), Git (git::https://github.com/org/repo), HTTP. Best practices (2025): Single responsibility (focused modules), semantic versioning, README with inputs/outputs, examples directory. Avoid mega-modules bundling unrelated resources. Use for: VPC setup, EKS clusters, security groups, common patterns.

99% confidence
A

Terraform builds a directed acyclic graph (DAG) to determine resource creation/destruction order automatically. Implicit dependencies (preferred): Resource references create automatic dependency - vpc_id = aws_vpc.main.id makes instance depend on VPC. Explicit dependencies: depends_on meta-argument when implicit insufficient (e.g., IAM eventual consistency):

resource "aws_instance" "web" {
  depends_on = [aws_iam_role_policy.policy]  # Wait for IAM propagation
}

Parallel execution: Independent resources created concurrently (Terraform default: 10 parallel operations, configure with -parallelism=N). Visualize: terraform graph | dot -Tsvg > graph.svg. Circular dependencies cause errors - must break cycle. Destroy order: Reverse of creation (instances before VPC). Best practice: Prefer implicit dependencies (clearer intent), use depends_on sparingly for cross-resource timing issues. Graph analysis critical for complex infrastructure understanding.

99% confidence
A

Workspaces manage multiple state files with same configuration. CLI commands: terraform workspace new dev, terraform workspace select prod, terraform workspace list, terraform workspace show (current). Each workspace has separate state in same backend. Access current workspace: terraform.workspace variable. HashiCorp recommendation (2025): Use separate directories for CLI/OSS Terraform when environments differ significantly - better visibility, smaller blast radius. Use workspaces only for: (1) Near-identical environments (dev/staging/prod with same resources), (2) Testing configuration changes in isolation, (3) Temporary parallel infrastructure. Limitations: Same backend, not appropriate for different credentials/access controls, invisible state (must run commands to see). HCP Terraform workspaces are different: Feature-rich with VCS integration, separate credentials, recommended for all environments. Best practice: CLI workspaces for similar envs, separate directories/repos for different architectures/teams.

99% confidence
A

Variables make configurations flexible and reusable. Declaration:

variable "region" {
  type        = string
  default     = "us-east-1"
  description = "AWS region for resources"
  validation {
    condition     = can(regex("^us-", var.region))
    error_message = "Region must be in US."
  }
}

Types: string, number, bool, list(type), map(type), set(type), object({...}), tuple([...]), any. Reference: var.region. Input methods (precedence order): (1) -var="region=us-west-2", (2) -var-file="prod.tfvars", (3) terraform.tfvars (auto-loaded), (4) *.auto.tfvars (auto-loaded alphabetically), (5) Environment variables TF_VAR_region, (6) Interactive prompt if no default. Sensitive variables: sensitive = true (hides in logs, still in state). Required variables: Omit default. Use for: Environment-specific values, secrets, resource sizing.

99% confidence
A

Outputs expose computed values after terraform apply. Definition:

output "instance_ip" {
  value       = aws_instance.web.public_ip
  description = "Public IP of web server"
  sensitive   = false
}

Access: terraform output (all outputs), terraform output instance_ip (specific output), terraform output -json (JSON format for automation). Use cases: (1) Display critical values (IPs, DNS names, database endpoints), (2) Share data between Terraform configurations via terraform_remote_state data source, (3) Integrate with CI/CD pipelines (GitHub Actions, GitLab CI), (4) Generate documentation automatically. Sensitive outputs: sensitive = true hides value in CLI output (still stored in state, viewable with terraform output -json). Module outputs: Expose values to parent module for composition. Query outputs without re-applying: terraform output reads from state. Essential for retrieving infrastructure information and integration.

99% confidence
A

Data sources query existing infrastructure/information without managing lifecycle. Read-only queries to providers. Syntax:

data "aws_ami" "ubuntu" {
  most_recent = true
  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
  }
  owners = ["099720109477"]  # Canonical
}
resource "aws_instance" "web" {
  ami = data.aws_ami.ubuntu.id  # Reference data source
}

Access: data.<type>.<name>.<attribute>. Use cases: (1) Reference existing resources (VPCs, security groups, subnets), (2) Lookup dynamic values (latest AMI, availability zones), (3) Cross-stack dependencies (terraform_remote_state), (4) External data (http, external). Difference from resources: Data sources query (read-only), resources create/update/delete (managed). Common data sources: aws_availability_zones, aws_ami, terraform_remote_state, aws_caller_identity. Refresh: Every terraform plan/apply. Essential for integrating with existing infrastructure.

99% confidence
A

Provisioners execute scripts on resources after creation but HashiCorp (2025) explicitly recommends them only as last resort. Three types: (1) local-exec - runs commands on machine running Terraform (CI/CD servers, local workstations), no prerequisites. (2) remote-exec - executes commands on remote resource via SSH/WinRM, requires connection block with credentials and network access, (3) file - copies files/directories to remote resource, also requires connection block. Critical limitation: Terraform cannot predict provisioner outcomes in terraform plan - only shows script will run, increasing operational risk and making plans unreliable. Provisioners introduce complexity, require direct network access, and obscure infrastructure intent. Failure behavior: Default marks resource "tainted" (destroyed on next apply), use on_failure = continue to suppress errors. Preferred alternatives (verified 2025): Cloud-init/user_data (native AWS/Azure/GCP, auto-scaling compatible), Packer (pre-built AMIs), Configuration Management tools (Ansible, Chef, Puppet - superior for complex scenarios), terraform_data resource (HashiCorp-recommended replacement for null_resource). Best practice: Never use provisioners without exhausting alternatives - complexity vs. benefit rarely justifies. Only use when no declarative alternative exists (edge cases like triggering external tools with local-exec).

99% confidence
A

2025 secret management best practices using Terraform 1.10+ features: (1) Ephemeral values (NEW in Terraform 1.10): Fetch secrets at runtime WITHOUT persisting to state/plan files. Use ephemeral resources (ephemeral keyword) for AWS Secrets Manager, Azure Key Vault, Kubernetes tokens. Providers supporting ephemeral: AWS, Azure, Kubernetes, GCP (Dec 2025+). (2) Write-only arguments (Terraform 1.11+): Sensitive values in resources not persisted to state. (3) Sensitive variables: sensitive = true hides from CLI output (still in state). (4) External secret stores: Vault, AWS Secrets Manager, Azure Key Vault via data sources. (5) Environment variables: TF_VAR_db_password for CI/CD. (6) HCP Terraform: Encrypted variable storage with workspace-level secrets. (7) Encrypted state: S3 with AES-256, Azure Storage encryption. (8) Never commit: .gitignore terraform.tfvars, *.tfvars, .terraform/. Critical: State contains secrets in plaintext (legacy) - use ephemeral values (modern). Best practice (2025): Ephemeral resources + external secret managers + encrypted remote state.

99% confidence
A

Lifecycle block customizes resource creation/destruction behavior for advanced scenarios. Arguments:

resource "aws_launch_template" "app" {
  lifecycle {
    create_before_destroy = true  # Create replacement before destroying original (zero-downtime)
    prevent_destroy       = true  # Block terraform destroy (must remove from config first)
    ignore_changes        = [tags, user_data]  # Ignore external modifications to these attributes
    replace_triggered_by  = [aws_instance.web.id]  # Force replacement when referenced resource changes
  }
}

(1) create_before_destroy: Create new resource before deleting old (essential for ASG launch templates, load balancer target groups). (2) prevent_destroy: Safety guard for critical resources (databases, S3 buckets) - apply fails if attempted. (3) ignore_changes: Ignore drift for externally-modified attributes (tags added by AWS Config, auto-scaling group size). (4) replace_triggered_by: Force replacement based on other resource changes (Terraform 1.2+). Use cases: Zero-downtime deployments, production safety guards, managing external modifications. Essential for advanced resource management.

99% confidence
A

Terraform provides 100+ built-in functions for value transformation (no user-defined functions). Categories: (1) Numeric: min(1, 2), max(5, 10), ceil(1.2), (2) String: upper(), lower(), format(), join(), split(), (3) Collection: length(), concat(), merge(), flatten(), distinct(), (4) Encoding: jsonencode(), yamldecode(), base64encode(), (5) Filesystem: file(), templatefile(), (6) Date/time: timestamp(), formatdate(), (7) Hash/crypto: md5(), sha256(), bcrypt(), (8) IP network: cidrsubnet(), cidrhost(), (9) Type conversion: tostring(), tonumber(), tobool(). Expressions: Conditionals var.env == "prod" ? "m5.large" : "t3.micro", for expressions [for s in var.subnets : s.id], splat aws_instance.web[*].id. Examples: cidrsubnet("10.0.0.0/16", 8, 1) = "10.0.1.0/24", merge({a=1}, {b=2}) = {a=1, b=2}. Use for: Dynamic subnet calculation, conditional resource sizing, data transformation. Essential for flexible, DRY configurations.

99% confidence
A

Meta-arguments for creating multiple similar resources. count (index-based):

resource "aws_instance" "server" {
  count         = 3
  instance_type = "t3.micro"
  tags = { Name = "server-${count.index}" }  # server-0, server-1, server-2
}
# Access: aws_instance.server[0].id

for_each (key-based, preferred):

resource "aws_instance" "server" {
  for_each      = toset(["web", "api", "worker"])
  instance_type = "t3.micro"
  tags = { Name = each.key }  # Access: each.key, each.value
}
# Access: aws_instance.server["web"].id

Differences: count uses numeric index (brittle if order changes - removing middle element recreates resources), for_each uses keys (stable - removing one key only affects that resource). Inputs: for_each accepts set or map. Best practice (2025): Prefer for_each for maintainability, use count only for simple numeric repetition or conditional creation (count = var.create ? 1 : 0). Essential for managing multiple instances without code duplication.

99% confidence
A

State locking prevents concurrent modifications that could corrupt infrastructure. When terraform apply runs, Terraform preemptively locks state so other users/instances cannot apply changes simultaneously. 2025 update: S3 backend now supports native locking (Terraform 1.10+) without DynamoDB via use_lockfile = true - creates .tflock file alongside state. Lock contains: Operation type, who initiated, timestamp, reason. Supported backends: S3 (native or DynamoDB), Azure Blob Storage (native), GCS, HCP Terraform, Consul. Lock acquisition: Automatic before any state-modifying operation (apply, destroy, import). Stuck locks: terraform force-unlock <lock-id> (use ONLY when certain operation crashed - never force unlock an active operation). Disable locking: -lock=false flag (dangerous, use ONLY for read operations like plan). Best practice (2025): Always use locking backend for teams, never disable locking for apply/destroy, investigate stuck locks before force-unlocking (check team communication, CloudTrail logs).

99% confidence
A

Terraform project structure (HashiCorp 2025 standard): Use directory-based environment separation with dedicated state per environment. Recommended layout:

terraform/
├── environments/
│   ├── dev/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│   │   ├── backend.tf
│   │   └── terraform.tfvars
│   ├── staging/
│   └── prod/
├── modules/
│   ├── networking/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│   │   └── README.md
│   ├── compute/
│   ├── database/
│   └── storage/
├── global/
│   ├── main.tf
│   └── terraform.tfvars
└── README.md

Core principles (HashiCorp + AWS best practices, 2025): (1) State splitting (critical): Separate state per environment (dev/staging/prod) with own backend configuration - minimizes blast radius if errors occur. Each env calls shared modules via relative paths. (2) Module organization: modules/ directory with focused, single-responsibility components (networking, compute, database, storage) - never create monolithic mega-modules. Each module requires main.tf, variables.tf, outputs.tf, README.md. (3) File organization: main.tf (resources), variables.tf (input declarations), outputs.tf (exposed values), versions.tf (version constraints), backend.tf (state backend config). Split into separate files (network.tf, iam.tf) only if main.tf exceeds 150 lines. (4) Environment-specific values: Store in terraform.tfvars per environment, NEVER hardcode in files. Use variables.tf for input declarations. (5) Remote backend with locking: Always use remote state (S3 with native locking v1.10+, Azure Storage, GCS, HCP Terraform) - no local .tfstate files in production. (6) Version control: .gitignore .terraform/, .tfstate, terraform.tfvars (secrets), .terraformrc. Always commit .terraform.lock.hcl. (7) Documentation: README.md in root and each module describing purpose, inputs, outputs, usage examples. (8) Monorepo vs Polyrepo decision: Monorepo benefits (shared modules, atomic changes) suit smaller teams; polyrepo (autonomy, separate lifecycles) suits large organizations. HashiCorp 2025 recommendation: Use directory-based separation for CLI/OSS Terraform, workspace-based for HCP Terraform with VCS integration.

99% confidence
A

Import existing infrastructure using modern import blocks (Terraform 1.5+) with automatic code generation:

# Step 1: Define import block
import {
  to = aws_instance.web
  id = "i-1234567890abcdef0"
}

Step 2: Generate configuration: terraform plan -generate-config-out=generated.tf (auto-creates resource blocks). Step 3: Review generated code (marked with # __generated__ by Terraform). Step 4: Run terraform apply to complete import. Legacy CLI import (still supported): terraform import aws_instance.web i-1234567890abcdef0 (requires manual configuration writing). Resource ID format varies by provider - check provider docs. Bulk import: Terraform 1.14+ supports terraform query to search infrastructure and generate import configs. Tools: Terraformer (bulk import), HCP Terraform import UI. 2025 best practice: Use import blocks + automatic code generation for maintainability. Verify: terraform plan should show no changes after import. Essential for migrating existing infrastructure to IaC.

99% confidence
A

State commands manipulate Terraform state safely without infrastructure changes: (1) terraform state list - Show all managed resources (aws_instance.web, aws_vpc.main), filter with patterns (terraform state list 'aws_instance.*'). (2) terraform state show aws_instance.web - Display detailed resource attributes (ID, IP, tags). (3) terraform state mv aws_instance.old aws_instance.new - Rename resources in state during refactoring (doesn't recreate resource). (4) terraform state rm aws_instance.web - Remove from Terraform management (resource continues running in cloud, no longer tracked). (5) terraform state pull - Export state JSON to stdout for inspection (terraform state pull > backup.tfstate). (6) terraform state push backup.tfstate - Import state (dangerous - use only for recovery). Use cases: Refactoring module structure, debugging state inconsistencies, migrating resources between states, manual state recovery. NEVER manually edit state JSON - always use these commands. Best practice: Backup state before manipulation (terraform state pull > backup-$(date +%Y%m%d).tfstate), test in non-production first. Essential for safe state maintenance.

99% confidence
A

HCP Terraform (rebranded from Terraform Cloud on April 22, 2024; IBM completed $6.4B HashiCorp acquisition February 27, 2025) is a SaaS platform for team collaboration and governance. Key features: (1) Remote state with locking and encryption, (2) VCS integration (GitHub, GitLab, Bitbucket) for automated runs, (3) Private module registry, (4) Policy as code (Sentinel for compliance), (5) Remote execution with run queues, (6) Cost estimation for AWS/Azure/GCP, (7) Workspace management (different from CLI workspaces - feature-rich with separate credentials), (8) Team RBAC and SSO, (9) Audit logging. Pricing (2025): Free tier (500 managed resources), paid tiers charge $0.10-$0.99 per resource/month. Example costs: 1,000 resources = $350/month, 10,000 resources = $10,200/month. Workflow: VCS-driven (Git push → automated plan/apply), API-driven (CI/CD integration), or CLI-driven. Limitations: Free tier allows only 1 concurrent run (others queue). Best for: Teams needing collaboration, governance, compliance. Alternative: Terraform Enterprise (self-hosted).

99% confidence
A

Terraform Enterprise is self-hosted HCP Terraform for organizations with strict security/compliance requirements. Deployed on-premises or customer-managed cloud (AWS, Azure, GCP). Includes all HCP Terraform features plus: (1) Full control over data location (data residency compliance), (2) Enterprise identity integration (SAML, LDAP, Active Directory), (3) Network isolation (private VPCs, no external ingress required), (4) Air-gapped deployments (no internet access needed), (5) Custom compliance policies, (6) No resource limits (vs HCP Terraform's tiered limits), (7) Integration with existing enterprise monitoring/logging. Pricing (2025): License-based model, typically $75,000/year minimum (Plus tier), $150,000/year for Enterprise features. AWS Marketplace: $15,000/year for 5 workspaces. Use when: HIPAA/PCI/SOX compliance requirements, data must stay in specific regions, existing enterprise SSO, internal direct access to systems needed. Trade-off: Higher cost and operational overhead vs HCP Terraform's zero-maintenance SaaS model. Best for: Large enterprises with dedicated platform teams.

99% confidence
A

Essential commands for code quality (2025 CI/CD standard): (1) terraform fmt - Auto-format HCL to canonical style (indentation, alignment). Use terraform fmt -check in CI to fail pipeline on formatting issues (exit code 0 = formatted, 3 = changes needed). Apply recursively: terraform fmt -recursive. (2) terraform validate - Check syntax, attribute names, resource types, provider schemas WITHOUT accessing remote state (works offline). Validates: HCL syntax, resource references, required attributes, type constraints. (3) terraform plan - Full validation against current state + preview changes. Pre-commit hooks (recommended):

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/antonbabenko/pre-commit-terraform
    rev: v1.88.0  # 2025 version
    hooks:
      - id: terraform_fmt
      - id: terraform_validate
      - id: terraform_docs  # Auto-generate README
      - id: tflint  # Linting for errors/best practices

CI/CD integration: Run terraform fmt -check && terraform validate in every pull request. Catches: Syntax errors, missing variables, invalid resource references, formatting drift. Essential for code quality gates.

99% confidence
A

Terraform 1.6+ includes built-in testing framework via terraform test command (generally available 2025). Test files (.tftest.hcl) contain run blocks executing real/mocked infrastructure:

# tests/vpc.tftest.hcl
run "create_vpc" {
  command = apply  # or plan for dry-run
  assert {
    condition     = aws_vpc.main.cidr_block == "10.0.0.0/16"
    error_message = "VPC CIDR mismatch"
  }
}

Mocking support (Terraform 1.7+): Mock provider responses for unit testing without real infrastructure. JUnit XML output (Terraform 1.11+): terraform test -junit-xml=report.xml for CI/CD integration. External tools: (1) Terratest (Go) - Integration testing deploying real resources, (2) tflint - Static analysis for errors/best practices, (3) terraform-compliance - BDD-style policy testing, (4) Checkov - Security scanning, (5) OPA/Sentinel - Policy as code. Testing strategy: tflint (static) → terraform test (unit/integration) → Terratest (end-to-end) → Sentinel (policy). Best practice (2025): Use built-in terraform test for most cases, Terratest for complex multi-service scenarios. Essential for reliable infrastructure.

99% confidence
A

Dynamic blocks generate nested repeatable blocks programmatically from variables/data sources. Use for: security group rules, tags, route table entries. Syntax:

variable "ingress_rules" {
  type = list(object({ port = number, protocol = string, cidr = list(string) }))
  default = [
    { port = 80, protocol = "tcp", cidr = ["0.0.0.0/0"] },
    { port = 443, protocol = "tcp", cidr = ["0.0.0.0/0"] }
  ]
}
resource "aws_security_group" "web" {
  dynamic "ingress" {
    for_each = var.ingress_rules
    iterator = rule  # Optional: customize reference name (default: block name)
    content {
      from_port   = rule.value.port
      to_port     = rule.value.port
      protocol    = rule.value.protocol
      cidr_blocks = rule.value.cidr
    }
  }
}

Access: rule.key (index), rule.value (object). Use iterator argument to customize reference name for clarity. Common uses: Security group rules (multiple ingress/egress), tags (conditional based on environment), IAM policy statements. Best practice: Use sparingly - complex dynamic blocks reduce readability. Prefer for_each on resources when possible.

99% confidence
A

Dynamic blocks limitations (2025): (1) Only work for repeatable nested blocks (ingress, egress, tag) - cannot create top-level resources, (2) Cannot nest dynamic blocks within other dynamic blocks, (3) Reduce code readability - requires understanding for_each logic, (4) Harder to debug - errors less obvious than static blocks, (5) Plan output less clear when many dynamic blocks present. Best practices: Use sparingly - only when block count is truly variable. Prefer alternatives: (1) for_each on resources (better - each resource explicitly visible in state), (2) Static blocks when count is fixed, (3) Locals for data transformation before use, (4) Separate modules for complex scenarios. When using dynamic blocks: Add comments explaining logic, keep for_each expression simple, use iterator for clarity, avoid complex nested conditionals. Anti-pattern: Dynamic blocks with complex conditionals inside - breaks into separate resources instead. 2025 recommendation: Favor explicit resource for_each over dynamic blocks for maintainability - dynamic blocks are last resort for nested configurations.

99% confidence
A

Terraform version constraints ensure reproducibility across environments and teams. Configure in versions.tf:

terraform {
  required_version = "~> 1.10"  # Recommended: Allows 1.10.x, excludes 1.11.0+
  # Alternatives:
  # required_version = ">= 1.10.0"  # Minimum version (looser)
  # required_version = "= 1.10.5"   # Exact version (strictest)
}

Constraint operators: = (exact), != (exclude), > >= < <= (comparison), ~> (pessimistic - allows rightmost version component to increment). Pessimistic examples: ~> 1.10.0 allows 1.10.x, ~> 1.10 allows 1.x. Commands: terraform version shows installed version, terraform -chdir=dir version checks specific directory. Best practices (2025): (1) Use pessimistic ~> constraints for flexibility with patch updates, (2) Test upgrades in non-production first, (3) Enforce version in CI/CD (terraform version check before apply), (4) Document version in README, (5) Upgrade regularly - Terraform 1.10+ includes critical features (ephemeral values, S3 native locking). Current version: Terraform 1.13.5 (latest stable, 2025). Essential for team consistency and reproducibility.

99% confidence
A

Provider version constraints ensure reproducible deployments across environments. Configure in versions.tf:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"  # 2025: AWS provider v6.0+ (breaking changes from v5)
    }
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.0"
    }
    kubernetes = {
      source  = "hashicorp/kubernetes"
      version = ">= 2.20.0"
    }
  }
}
provider "aws" { region = "us-east-1" }

Lock file .terraform.lock.hcl: Records exact provider versions + checksums (prevents supply chain attacks). Auto-generated on terraform init, commit to version control. Commands: (1) terraform init -upgrade - Update providers to latest allowed by constraints, (2) terraform providers - Show installed providers, (3) terraform providers lock - Update lock file for multiple platforms, (4) terraform providers schema -json - View provider schemas. Best practices (2025): (1) Use pessimistic ~> constraints (balance stability + security patches), (2) ALWAYS commit .terraform.lock.hcl to Git, (3) Test provider upgrades in dev first (especially major versions - AWS v6 breaks S3/IAM/RDS configs), (4) Monitor provider release notes (AWS crossed 5 billion downloads, releasing frequently), (5) Pin exact versions for critical production systems. Provider registry: registry.terraform.io (5,706+ providers).

99% confidence
A

Common anti-patterns and production mistakes (2025): (1) Monolithic modules: Large 'do-everything' modules bundling many resources across unrelated domains, leading to inflated state files, brittle updates, high coupling. HashiCorp identifies two scaling anti-patterns: module proliferation, then mega-modules. Fix: Break into smaller, focused components (networking, compute, storage). (2) Monolithic state files: Single large state increases blast radius (potential impact of change/corruption), slows plans/applies, causes team conflicts. Fix: Split state by environment, component, region. (3) Manual state editing: Corrupts state structure. Fix: Use terraform state commands. (4) No remote backend: Local .tfstate files risk data loss, prevent collaboration. Fix: Use S3 + DynamoDB, Azure Storage, Terraform Cloud. (5) Hardcoded values: ARNs, regions, CIDRs create inflexible code. Fix: Pass as input variables. (6) Committing secrets: Hardcoding credentials in config makes environment-specific management difficult. Fix: Use external secret stores (Vault, AWS Secrets Manager). (7) No version constraints: Causes reproducibility issues. Fix: Pin terraform and provider versions. (8) Testing gaps: Skipping terraform validate, terraform plan in CI/CD leaves room for regressions. Fix: Automated testing with Terratest. (9) Out-of-band changes: Making changes via cloud console causes configuration drift. Fix: All changes through Terraform. (10) No state locking: Concurrent modifications risk corruption. Fix: Use locking backend. (11) Overusing provisioners: Cannot predict outcomes, increases operational risk. Fix: Prefer cloud-init, user-data, custom AMIs. (12) Complex for_each/dynamic blocks: Hard to read and maintain. Fix: Keep logic simple, use comments. Warning: Terraform makes it easy to start but considerably more challenging to get right. Teams discover this after accumulating significant technical debt. Simple deployments become maintenance nightmares when overlooking best practices.

99% confidence
A

Terraform is HashiCorp's declarative infrastructure as code (IaC) tool that enables safe, efficient infrastructure provisioning across 5,710+ providers (2025). Current version: Terraform 1.13.5 (latest stable GA), 1.14.0 in RC. Unlike imperative tools, Terraform uses a declarative approach where you describe desired end state in HCL (HashiCorp Configuration Language), and Terraform determines execution path. Core workflow: write .tf configuration → terraform init (download providers) → terraform plan (preview changes) → terraform apply (execute). Terraform maintains JSON state file tracking real-world resources, enabling change detection, dependency resolution, and drift prevention. Multi-cloud support: AWS, Azure, GCP, Kubernetes, Docker, GitHub via unified CLI. Industry standard for IaC with 5+ billion provider downloads (AWS provider v6.21.0 latest, November 2025).

99% confidence
A

Terraform 1.13.5 stable (1.14.0 RC) provides essential features for modern infrastructure automation (2025): (1) Declarative HCL syntax for human-readable configuration with IDE support, (2) Execution plans (terraform plan) preview changes before applying with cost estimation in HCP Terraform, (3) Resource dependency graph for automatic ordering and parallel execution, (4) State management tracking infrastructure with remote backends (S3, Azure Storage, GCS), (5) Multi-cloud support across 5,710+ providers. Advanced features: Workspaces for environment isolation, modules from Terraform Registry (20,956+ modules), data sources for querying existing infrastructure, lifecycle meta-arguments (create_before_destroy, prevent_destroy), built-in testing framework (terraform test in v1.6+, mocking in v1.7+), ephemeral values for secrets (v1.10+), import blocks with automatic code generation (v1.5+), native S3 state locking without DynamoDB (v1.10+). Benefits: Infrastructure versioning via Git, reproducible deployments, team collaboration, automated compliance.

99% confidence
A

HCL (HashiCorp Configuration Language) is Terraform's declarative, human-readable language for infrastructure definition. HCL2 (introduced Terraform 0.12+, current standard in 2025) adds type handling, expressions, for_each, and dynamic blocks. Basic structure: resource blocks (resource "aws_instance" "web" { ami = "ami-123" }), data sources, variables, outputs, providers. Syntax: Blocks with arguments and nested blocks. Comments: # or //. Standard file structure (2025 best practice): main.tf (core resources), variables.tf (input declarations), outputs.tf (output values), versions.tf (Terraform and provider version constraints), providers.tf (provider configuration). Declarative nature means order of blocks/files is generally insignificant - Terraform builds dependency graph automatically. HCL files use .tf extension, must be valid UTF-8 encoded. Advanced features: Conditionals (condition ? true_val : false_val), for expressions, functions (cidrsubnet, merge, lookup).

99% confidence
A

Providers are plugins that manage resource lifecycle by interacting with cloud platform/service APIs. Terraform Registry hosts 5,710+ providers (2025), with top 20 providers accounting for 85% of downloads. Configure in versions.tf:

terraform {
  required_providers {
    aws = { source = "hashicorp/aws", version = "~> 6.0" }  # 2025: v6.21.0 latest
    azurerm = { source = "hashicorp/azurerm", version = "~> 3.0" }
  }
}
provider "aws" { region = "us-east-1" }

Providers handle: Authentication (credentials), API calls (CRUD operations), schema validation, state updates. Multiple instances via aliases for multi-region: provider "aws" { alias = "us-west", region = "us-west-2" }. Lock file .terraform.lock.hcl pins exact versions. Install via terraform init. Major providers (2025): AWS (5B+ downloads, v6.21.0), Azure (azurerm), GCP, Kubernetes, Docker. Provider support for ephemeral resources (v1.10+): AWS, Azure, Kubernetes, random.

99% confidence
A

Core workflow commands (Terraform 1.10+): (1) terraform init - Initialize directory, download providers from registry, configure backend. Safe to re-run. (2) terraform validate - Check configuration syntax and consistency without accessing remote state. (3) terraform plan - Preview changes, show execution plan comparing current state to desired config. Use -out=plan.tfplan to save plan. (4) terraform apply - Execute changes, prompts for confirmation (use -auto-approve in CI/CD). (5) terraform destroy - Remove all managed resources. Additional commands: terraform fmt (format HCL to canonical style), terraform output (display output values), terraform show (inspect state/plan), terraform test (run tests, v1.6+), terraform import (import existing resources). Best practice workflow: write HCL → init → validate → plan → apply → test. Always run plan before apply in production.

99% confidence
A

Terraform state is a JSON file (terraform.tfstate) that maps HCL configuration to real-world infrastructure resources, serving as Terraform's source of truth. State contains: resource IDs (e.g., i-1234567890abcdef0), computed attributes (public IPs, DNS names), resource metadata, dependency graphs, provider configuration. State enables: (1) Change detection - Terraform compares desired config to current state during terraform plan, (2) Performance optimization - Avoids querying every resource on each run, (3) Dependency tracking - Ensures resources destroyed in correct order. State format: Human-readable JSON but NEVER manually edit (use terraform state commands instead). Critical: State contains sensitive data (passwords, keys) in plaintext - always encrypt and restrict access. Without state, Terraform cannot determine what infrastructure exists or what changes to make. Default: Local file (terraform.tfstate), production: Remote backend (S3, Azure Storage, HCP Terraform).

99% confidence
A

State management is critical for infrastructure safety and team collaboration (2025 best practices): (1) Change detection - Enables terraform plan to show precise diffs between desired vs actual infrastructure, (2) Dependency resolution - Tracks resource relationships ensuring correct creation/destruction order (destroy VMs before VPC), (3) Performance - Cached metadata avoids querying all cloud resources on every run, (4) Team collaboration - Remote state with locking prevents concurrent modifications that corrupt infrastructure, (5) Security - State contains sensitive data (passwords, private keys) requiring encryption at rest (AES-256) and in transit (TLS), (6) Blast radius control - Split state by environment/component to limit impact of errors. Poor state management causes: Configuration drift (manual changes untracked), resource conflicts (duplicate resources), infrastructure corruption (lost state = lost infrastructure tracking). Production requirements (2025): Remote backend (S3, Azure Storage, HCP Terraform), state locking enabled, encryption enabled, version control for configs (NOT state files), state splitting by environment.

99% confidence
A

Backends determine state storage location and operation execution. Types: local (default, terraform.tfstate in working directory), remote (S3, Azure Storage, GCS, HCP Terraform). BREAKING CHANGE (Terraform 1.10+, 2025): S3 now supports native state locking without DynamoDB. Configure in backend.tf:

terraform {
  backend "s3" {
    bucket         = "my-terraform-state"
    key            = "production/terraform.tfstate"
    region         = "us-east-1"
    encrypt        = true
    use_lockfile   = true  # NEW: Native S3 locking, no DynamoDB needed
  }
}

S3 creates .tflock file alongside state for locking. Legacy DynamoDB locking deprecated, will be removed in future versions. Initialize: terraform init. Migrate backends: terraform init -migrate-state. Important: Backend config cannot use variables (must be static values or use -backend-config flag). Production: Always enable versioning on S3 bucket for state recovery.

99% confidence
A

Remote state management provides critical benefits for team-based infrastructure (2025 best practices): (1) Team collaboration - Shared access via S3/Azure Storage enables multiple engineers to work simultaneously, (2) State locking - Prevents concurrent modifications that corrupt infrastructure (automatic with S3 native locking in Terraform 1.10+), (3) Encryption - AES-256 encryption at rest protects sensitive data (passwords, keys), (4) Versioning - S3 versioning enables rollback after accidental corruption, (5) Durability - 99.999999999% (11 nines) durability with S3 Standard vs risky local files, (6) CI/CD integration - Automated pipelines access shared state without local dependency, (7) Audit logging - CloudTrail/Azure Monitor tracks all state access for compliance, (8) Consistency checking - Backend validates state integrity. Popular backends (2025): S3 with native locking (no DynamoDB), Azure Blob Storage, GCS, HCP Terraform. Remote state mandatory for production - eliminates single points of failure from local state files.

99% confidence
A

Modules are reusable Terraform configurations that create organization, reduce duplication, and standardize infrastructure. Terraform Registry hosts 20,956+ modules (2025). Module structure: Directory with .tf files. Call modules:

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"  # Registry module
  version = "5.0.0"  # Always pin version
  cidr    = "10.0.0.0/16"  # Input variable
}
# Local module
module "app" {
  source = "./modules/application"
  env    = "production"
}

Inputs: variable blocks, outputs: output blocks expose values to parent. Module sources: Local path (./modules/vpc), Terraform Registry (terraform-aws-modules/vpc/aws), Git (git::https://github.com/org/repo), HTTP. Best practices (2025): Single responsibility (focused modules), semantic versioning, README with inputs/outputs, examples directory. Avoid mega-modules bundling unrelated resources. Use for: VPC setup, EKS clusters, security groups, common patterns.

99% confidence
A

Terraform builds a directed acyclic graph (DAG) to determine resource creation/destruction order automatically. Implicit dependencies (preferred): Resource references create automatic dependency - vpc_id = aws_vpc.main.id makes instance depend on VPC. Explicit dependencies: depends_on meta-argument when implicit insufficient (e.g., IAM eventual consistency):

resource "aws_instance" "web" {
  depends_on = [aws_iam_role_policy.policy]  # Wait for IAM propagation
}

Parallel execution: Independent resources created concurrently (Terraform default: 10 parallel operations, configure with -parallelism=N). Visualize: terraform graph | dot -Tsvg > graph.svg. Circular dependencies cause errors - must break cycle. Destroy order: Reverse of creation (instances before VPC). Best practice: Prefer implicit dependencies (clearer intent), use depends_on sparingly for cross-resource timing issues. Graph analysis critical for complex infrastructure understanding.

99% confidence
A

Workspaces manage multiple state files with same configuration. CLI commands: terraform workspace new dev, terraform workspace select prod, terraform workspace list, terraform workspace show (current). Each workspace has separate state in same backend. Access current workspace: terraform.workspace variable. HashiCorp recommendation (2025): Use separate directories for CLI/OSS Terraform when environments differ significantly - better visibility, smaller blast radius. Use workspaces only for: (1) Near-identical environments (dev/staging/prod with same resources), (2) Testing configuration changes in isolation, (3) Temporary parallel infrastructure. Limitations: Same backend, not appropriate for different credentials/access controls, invisible state (must run commands to see). HCP Terraform workspaces are different: Feature-rich with VCS integration, separate credentials, recommended for all environments. Best practice: CLI workspaces for similar envs, separate directories/repos for different architectures/teams.

99% confidence
A

Variables make configurations flexible and reusable. Declaration:

variable "region" {
  type        = string
  default     = "us-east-1"
  description = "AWS region for resources"
  validation {
    condition     = can(regex("^us-", var.region))
    error_message = "Region must be in US."
  }
}

Types: string, number, bool, list(type), map(type), set(type), object({...}), tuple([...]), any. Reference: var.region. Input methods (precedence order): (1) -var="region=us-west-2", (2) -var-file="prod.tfvars", (3) terraform.tfvars (auto-loaded), (4) *.auto.tfvars (auto-loaded alphabetically), (5) Environment variables TF_VAR_region, (6) Interactive prompt if no default. Sensitive variables: sensitive = true (hides in logs, still in state). Required variables: Omit default. Use for: Environment-specific values, secrets, resource sizing.

99% confidence
A

Outputs expose computed values after terraform apply. Definition:

output "instance_ip" {
  value       = aws_instance.web.public_ip
  description = "Public IP of web server"
  sensitive   = false
}

Access: terraform output (all outputs), terraform output instance_ip (specific output), terraform output -json (JSON format for automation). Use cases: (1) Display critical values (IPs, DNS names, database endpoints), (2) Share data between Terraform configurations via terraform_remote_state data source, (3) Integrate with CI/CD pipelines (GitHub Actions, GitLab CI), (4) Generate documentation automatically. Sensitive outputs: sensitive = true hides value in CLI output (still stored in state, viewable with terraform output -json). Module outputs: Expose values to parent module for composition. Query outputs without re-applying: terraform output reads from state. Essential for retrieving infrastructure information and integration.

99% confidence
A

Data sources query existing infrastructure/information without managing lifecycle. Read-only queries to providers. Syntax:

data "aws_ami" "ubuntu" {
  most_recent = true
  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
  }
  owners = ["099720109477"]  # Canonical
}
resource "aws_instance" "web" {
  ami = data.aws_ami.ubuntu.id  # Reference data source
}

Access: data.<type>.<name>.<attribute>. Use cases: (1) Reference existing resources (VPCs, security groups, subnets), (2) Lookup dynamic values (latest AMI, availability zones), (3) Cross-stack dependencies (terraform_remote_state), (4) External data (http, external). Difference from resources: Data sources query (read-only), resources create/update/delete (managed). Common data sources: aws_availability_zones, aws_ami, terraform_remote_state, aws_caller_identity. Refresh: Every terraform plan/apply. Essential for integrating with existing infrastructure.

99% confidence
A

Provisioners execute scripts on resources after creation but HashiCorp (2025) explicitly recommends them only as last resort. Three types: (1) local-exec - runs commands on machine running Terraform (CI/CD servers, local workstations), no prerequisites. (2) remote-exec - executes commands on remote resource via SSH/WinRM, requires connection block with credentials and network access, (3) file - copies files/directories to remote resource, also requires connection block. Critical limitation: Terraform cannot predict provisioner outcomes in terraform plan - only shows script will run, increasing operational risk and making plans unreliable. Provisioners introduce complexity, require direct network access, and obscure infrastructure intent. Failure behavior: Default marks resource "tainted" (destroyed on next apply), use on_failure = continue to suppress errors. Preferred alternatives (verified 2025): Cloud-init/user_data (native AWS/Azure/GCP, auto-scaling compatible), Packer (pre-built AMIs), Configuration Management tools (Ansible, Chef, Puppet - superior for complex scenarios), terraform_data resource (HashiCorp-recommended replacement for null_resource). Best practice: Never use provisioners without exhausting alternatives - complexity vs. benefit rarely justifies. Only use when no declarative alternative exists (edge cases like triggering external tools with local-exec).

99% confidence
A

2025 secret management best practices using Terraform 1.10+ features: (1) Ephemeral values (NEW in Terraform 1.10): Fetch secrets at runtime WITHOUT persisting to state/plan files. Use ephemeral resources (ephemeral keyword) for AWS Secrets Manager, Azure Key Vault, Kubernetes tokens. Providers supporting ephemeral: AWS, Azure, Kubernetes, GCP (Dec 2025+). (2) Write-only arguments (Terraform 1.11+): Sensitive values in resources not persisted to state. (3) Sensitive variables: sensitive = true hides from CLI output (still in state). (4) External secret stores: Vault, AWS Secrets Manager, Azure Key Vault via data sources. (5) Environment variables: TF_VAR_db_password for CI/CD. (6) HCP Terraform: Encrypted variable storage with workspace-level secrets. (7) Encrypted state: S3 with AES-256, Azure Storage encryption. (8) Never commit: .gitignore terraform.tfvars, *.tfvars, .terraform/. Critical: State contains secrets in plaintext (legacy) - use ephemeral values (modern). Best practice (2025): Ephemeral resources + external secret managers + encrypted remote state.

99% confidence
A

Lifecycle block customizes resource creation/destruction behavior for advanced scenarios. Arguments:

resource "aws_launch_template" "app" {
  lifecycle {
    create_before_destroy = true  # Create replacement before destroying original (zero-downtime)
    prevent_destroy       = true  # Block terraform destroy (must remove from config first)
    ignore_changes        = [tags, user_data]  # Ignore external modifications to these attributes
    replace_triggered_by  = [aws_instance.web.id]  # Force replacement when referenced resource changes
  }
}

(1) create_before_destroy: Create new resource before deleting old (essential for ASG launch templates, load balancer target groups). (2) prevent_destroy: Safety guard for critical resources (databases, S3 buckets) - apply fails if attempted. (3) ignore_changes: Ignore drift for externally-modified attributes (tags added by AWS Config, auto-scaling group size). (4) replace_triggered_by: Force replacement based on other resource changes (Terraform 1.2+). Use cases: Zero-downtime deployments, production safety guards, managing external modifications. Essential for advanced resource management.

99% confidence
A

Terraform provides 100+ built-in functions for value transformation (no user-defined functions). Categories: (1) Numeric: min(1, 2), max(5, 10), ceil(1.2), (2) String: upper(), lower(), format(), join(), split(), (3) Collection: length(), concat(), merge(), flatten(), distinct(), (4) Encoding: jsonencode(), yamldecode(), base64encode(), (5) Filesystem: file(), templatefile(), (6) Date/time: timestamp(), formatdate(), (7) Hash/crypto: md5(), sha256(), bcrypt(), (8) IP network: cidrsubnet(), cidrhost(), (9) Type conversion: tostring(), tonumber(), tobool(). Expressions: Conditionals var.env == "prod" ? "m5.large" : "t3.micro", for expressions [for s in var.subnets : s.id], splat aws_instance.web[*].id. Examples: cidrsubnet("10.0.0.0/16", 8, 1) = "10.0.1.0/24", merge({a=1}, {b=2}) = {a=1, b=2}. Use for: Dynamic subnet calculation, conditional resource sizing, data transformation. Essential for flexible, DRY configurations.

99% confidence
A

Meta-arguments for creating multiple similar resources. count (index-based):

resource "aws_instance" "server" {
  count         = 3
  instance_type = "t3.micro"
  tags = { Name = "server-${count.index}" }  # server-0, server-1, server-2
}
# Access: aws_instance.server[0].id

for_each (key-based, preferred):

resource "aws_instance" "server" {
  for_each      = toset(["web", "api", "worker"])
  instance_type = "t3.micro"
  tags = { Name = each.key }  # Access: each.key, each.value
}
# Access: aws_instance.server["web"].id

Differences: count uses numeric index (brittle if order changes - removing middle element recreates resources), for_each uses keys (stable - removing one key only affects that resource). Inputs: for_each accepts set or map. Best practice (2025): Prefer for_each for maintainability, use count only for simple numeric repetition or conditional creation (count = var.create ? 1 : 0). Essential for managing multiple instances without code duplication.

99% confidence
A

State locking prevents concurrent modifications that could corrupt infrastructure. When terraform apply runs, Terraform preemptively locks state so other users/instances cannot apply changes simultaneously. 2025 update: S3 backend now supports native locking (Terraform 1.10+) without DynamoDB via use_lockfile = true - creates .tflock file alongside state. Lock contains: Operation type, who initiated, timestamp, reason. Supported backends: S3 (native or DynamoDB), Azure Blob Storage (native), GCS, HCP Terraform, Consul. Lock acquisition: Automatic before any state-modifying operation (apply, destroy, import). Stuck locks: terraform force-unlock <lock-id> (use ONLY when certain operation crashed - never force unlock an active operation). Disable locking: -lock=false flag (dangerous, use ONLY for read operations like plan). Best practice (2025): Always use locking backend for teams, never disable locking for apply/destroy, investigate stuck locks before force-unlocking (check team communication, CloudTrail logs).

99% confidence
A

Terraform project structure (HashiCorp 2025 standard): Use directory-based environment separation with dedicated state per environment. Recommended layout:

terraform/
├── environments/
│   ├── dev/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│   │   ├── backend.tf
│   │   └── terraform.tfvars
│   ├── staging/
│   └── prod/
├── modules/
│   ├── networking/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│   │   └── README.md
│   ├── compute/
│   ├── database/
│   └── storage/
├── global/
│   ├── main.tf
│   └── terraform.tfvars
└── README.md

Core principles (HashiCorp + AWS best practices, 2025): (1) State splitting (critical): Separate state per environment (dev/staging/prod) with own backend configuration - minimizes blast radius if errors occur. Each env calls shared modules via relative paths. (2) Module organization: modules/ directory with focused, single-responsibility components (networking, compute, database, storage) - never create monolithic mega-modules. Each module requires main.tf, variables.tf, outputs.tf, README.md. (3) File organization: main.tf (resources), variables.tf (input declarations), outputs.tf (exposed values), versions.tf (version constraints), backend.tf (state backend config). Split into separate files (network.tf, iam.tf) only if main.tf exceeds 150 lines. (4) Environment-specific values: Store in terraform.tfvars per environment, NEVER hardcode in files. Use variables.tf for input declarations. (5) Remote backend with locking: Always use remote state (S3 with native locking v1.10+, Azure Storage, GCS, HCP Terraform) - no local .tfstate files in production. (6) Version control: .gitignore .terraform/, .tfstate, terraform.tfvars (secrets), .terraformrc. Always commit .terraform.lock.hcl. (7) Documentation: README.md in root and each module describing purpose, inputs, outputs, usage examples. (8) Monorepo vs Polyrepo decision: Monorepo benefits (shared modules, atomic changes) suit smaller teams; polyrepo (autonomy, separate lifecycles) suits large organizations. HashiCorp 2025 recommendation: Use directory-based separation for CLI/OSS Terraform, workspace-based for HCP Terraform with VCS integration.

99% confidence
A

Import existing infrastructure using modern import blocks (Terraform 1.5+) with automatic code generation:

# Step 1: Define import block
import {
  to = aws_instance.web
  id = "i-1234567890abcdef0"
}

Step 2: Generate configuration: terraform plan -generate-config-out=generated.tf (auto-creates resource blocks). Step 3: Review generated code (marked with # __generated__ by Terraform). Step 4: Run terraform apply to complete import. Legacy CLI import (still supported): terraform import aws_instance.web i-1234567890abcdef0 (requires manual configuration writing). Resource ID format varies by provider - check provider docs. Bulk import: Terraform 1.14+ supports terraform query to search infrastructure and generate import configs. Tools: Terraformer (bulk import), HCP Terraform import UI. 2025 best practice: Use import blocks + automatic code generation for maintainability. Verify: terraform plan should show no changes after import. Essential for migrating existing infrastructure to IaC.

99% confidence
A

State commands manipulate Terraform state safely without infrastructure changes: (1) terraform state list - Show all managed resources (aws_instance.web, aws_vpc.main), filter with patterns (terraform state list 'aws_instance.*'). (2) terraform state show aws_instance.web - Display detailed resource attributes (ID, IP, tags). (3) terraform state mv aws_instance.old aws_instance.new - Rename resources in state during refactoring (doesn't recreate resource). (4) terraform state rm aws_instance.web - Remove from Terraform management (resource continues running in cloud, no longer tracked). (5) terraform state pull - Export state JSON to stdout for inspection (terraform state pull > backup.tfstate). (6) terraform state push backup.tfstate - Import state (dangerous - use only for recovery). Use cases: Refactoring module structure, debugging state inconsistencies, migrating resources between states, manual state recovery. NEVER manually edit state JSON - always use these commands. Best practice: Backup state before manipulation (terraform state pull > backup-$(date +%Y%m%d).tfstate), test in non-production first. Essential for safe state maintenance.

99% confidence
A

HCP Terraform (rebranded from Terraform Cloud on April 22, 2024; IBM completed $6.4B HashiCorp acquisition February 27, 2025) is a SaaS platform for team collaboration and governance. Key features: (1) Remote state with locking and encryption, (2) VCS integration (GitHub, GitLab, Bitbucket) for automated runs, (3) Private module registry, (4) Policy as code (Sentinel for compliance), (5) Remote execution with run queues, (6) Cost estimation for AWS/Azure/GCP, (7) Workspace management (different from CLI workspaces - feature-rich with separate credentials), (8) Team RBAC and SSO, (9) Audit logging. Pricing (2025): Free tier (500 managed resources), paid tiers charge $0.10-$0.99 per resource/month. Example costs: 1,000 resources = $350/month, 10,000 resources = $10,200/month. Workflow: VCS-driven (Git push → automated plan/apply), API-driven (CI/CD integration), or CLI-driven. Limitations: Free tier allows only 1 concurrent run (others queue). Best for: Teams needing collaboration, governance, compliance. Alternative: Terraform Enterprise (self-hosted).

99% confidence
A

Terraform Enterprise is self-hosted HCP Terraform for organizations with strict security/compliance requirements. Deployed on-premises or customer-managed cloud (AWS, Azure, GCP). Includes all HCP Terraform features plus: (1) Full control over data location (data residency compliance), (2) Enterprise identity integration (SAML, LDAP, Active Directory), (3) Network isolation (private VPCs, no external ingress required), (4) Air-gapped deployments (no internet access needed), (5) Custom compliance policies, (6) No resource limits (vs HCP Terraform's tiered limits), (7) Integration with existing enterprise monitoring/logging. Pricing (2025): License-based model, typically $75,000/year minimum (Plus tier), $150,000/year for Enterprise features. AWS Marketplace: $15,000/year for 5 workspaces. Use when: HIPAA/PCI/SOX compliance requirements, data must stay in specific regions, existing enterprise SSO, internal direct access to systems needed. Trade-off: Higher cost and operational overhead vs HCP Terraform's zero-maintenance SaaS model. Best for: Large enterprises with dedicated platform teams.

99% confidence
A

Essential commands for code quality (2025 CI/CD standard): (1) terraform fmt - Auto-format HCL to canonical style (indentation, alignment). Use terraform fmt -check in CI to fail pipeline on formatting issues (exit code 0 = formatted, 3 = changes needed). Apply recursively: terraform fmt -recursive. (2) terraform validate - Check syntax, attribute names, resource types, provider schemas WITHOUT accessing remote state (works offline). Validates: HCL syntax, resource references, required attributes, type constraints. (3) terraform plan - Full validation against current state + preview changes. Pre-commit hooks (recommended):

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/antonbabenko/pre-commit-terraform
    rev: v1.88.0  # 2025 version
    hooks:
      - id: terraform_fmt
      - id: terraform_validate
      - id: terraform_docs  # Auto-generate README
      - id: tflint  # Linting for errors/best practices

CI/CD integration: Run terraform fmt -check && terraform validate in every pull request. Catches: Syntax errors, missing variables, invalid resource references, formatting drift. Essential for code quality gates.

99% confidence
A

Terraform 1.6+ includes built-in testing framework via terraform test command (generally available 2025). Test files (.tftest.hcl) contain run blocks executing real/mocked infrastructure:

# tests/vpc.tftest.hcl
run "create_vpc" {
  command = apply  # or plan for dry-run
  assert {
    condition     = aws_vpc.main.cidr_block == "10.0.0.0/16"
    error_message = "VPC CIDR mismatch"
  }
}

Mocking support (Terraform 1.7+): Mock provider responses for unit testing without real infrastructure. JUnit XML output (Terraform 1.11+): terraform test -junit-xml=report.xml for CI/CD integration. External tools: (1) Terratest (Go) - Integration testing deploying real resources, (2) tflint - Static analysis for errors/best practices, (3) terraform-compliance - BDD-style policy testing, (4) Checkov - Security scanning, (5) OPA/Sentinel - Policy as code. Testing strategy: tflint (static) → terraform test (unit/integration) → Terratest (end-to-end) → Sentinel (policy). Best practice (2025): Use built-in terraform test for most cases, Terratest for complex multi-service scenarios. Essential for reliable infrastructure.

99% confidence
A

Dynamic blocks generate nested repeatable blocks programmatically from variables/data sources. Use for: security group rules, tags, route table entries. Syntax:

variable "ingress_rules" {
  type = list(object({ port = number, protocol = string, cidr = list(string) }))
  default = [
    { port = 80, protocol = "tcp", cidr = ["0.0.0.0/0"] },
    { port = 443, protocol = "tcp", cidr = ["0.0.0.0/0"] }
  ]
}
resource "aws_security_group" "web" {
  dynamic "ingress" {
    for_each = var.ingress_rules
    iterator = rule  # Optional: customize reference name (default: block name)
    content {
      from_port   = rule.value.port
      to_port     = rule.value.port
      protocol    = rule.value.protocol
      cidr_blocks = rule.value.cidr
    }
  }
}

Access: rule.key (index), rule.value (object). Use iterator argument to customize reference name for clarity. Common uses: Security group rules (multiple ingress/egress), tags (conditional based on environment), IAM policy statements. Best practice: Use sparingly - complex dynamic blocks reduce readability. Prefer for_each on resources when possible.

99% confidence
A

Dynamic blocks limitations (2025): (1) Only work for repeatable nested blocks (ingress, egress, tag) - cannot create top-level resources, (2) Cannot nest dynamic blocks within other dynamic blocks, (3) Reduce code readability - requires understanding for_each logic, (4) Harder to debug - errors less obvious than static blocks, (5) Plan output less clear when many dynamic blocks present. Best practices: Use sparingly - only when block count is truly variable. Prefer alternatives: (1) for_each on resources (better - each resource explicitly visible in state), (2) Static blocks when count is fixed, (3) Locals for data transformation before use, (4) Separate modules for complex scenarios. When using dynamic blocks: Add comments explaining logic, keep for_each expression simple, use iterator for clarity, avoid complex nested conditionals. Anti-pattern: Dynamic blocks with complex conditionals inside - breaks into separate resources instead. 2025 recommendation: Favor explicit resource for_each over dynamic blocks for maintainability - dynamic blocks are last resort for nested configurations.

99% confidence
A

Terraform version constraints ensure reproducibility across environments and teams. Configure in versions.tf:

terraform {
  required_version = "~> 1.10"  # Recommended: Allows 1.10.x, excludes 1.11.0+
  # Alternatives:
  # required_version = ">= 1.10.0"  # Minimum version (looser)
  # required_version = "= 1.10.5"   # Exact version (strictest)
}

Constraint operators: = (exact), != (exclude), > >= < <= (comparison), ~> (pessimistic - allows rightmost version component to increment). Pessimistic examples: ~> 1.10.0 allows 1.10.x, ~> 1.10 allows 1.x. Commands: terraform version shows installed version, terraform -chdir=dir version checks specific directory. Best practices (2025): (1) Use pessimistic ~> constraints for flexibility with patch updates, (2) Test upgrades in non-production first, (3) Enforce version in CI/CD (terraform version check before apply), (4) Document version in README, (5) Upgrade regularly - Terraform 1.10+ includes critical features (ephemeral values, S3 native locking). Current version: Terraform 1.13.5 (latest stable, 2025). Essential for team consistency and reproducibility.

99% confidence
A

Provider version constraints ensure reproducible deployments across environments. Configure in versions.tf:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"  # 2025: AWS provider v6.0+ (breaking changes from v5)
    }
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.0"
    }
    kubernetes = {
      source  = "hashicorp/kubernetes"
      version = ">= 2.20.0"
    }
  }
}
provider "aws" { region = "us-east-1" }

Lock file .terraform.lock.hcl: Records exact provider versions + checksums (prevents supply chain attacks). Auto-generated on terraform init, commit to version control. Commands: (1) terraform init -upgrade - Update providers to latest allowed by constraints, (2) terraform providers - Show installed providers, (3) terraform providers lock - Update lock file for multiple platforms, (4) terraform providers schema -json - View provider schemas. Best practices (2025): (1) Use pessimistic ~> constraints (balance stability + security patches), (2) ALWAYS commit .terraform.lock.hcl to Git, (3) Test provider upgrades in dev first (especially major versions - AWS v6 breaks S3/IAM/RDS configs), (4) Monitor provider release notes (AWS crossed 5 billion downloads, releasing frequently), (5) Pin exact versions for critical production systems. Provider registry: registry.terraform.io (5,706+ providers).

99% confidence
A

Common anti-patterns and production mistakes (2025): (1) Monolithic modules: Large 'do-everything' modules bundling many resources across unrelated domains, leading to inflated state files, brittle updates, high coupling. HashiCorp identifies two scaling anti-patterns: module proliferation, then mega-modules. Fix: Break into smaller, focused components (networking, compute, storage). (2) Monolithic state files: Single large state increases blast radius (potential impact of change/corruption), slows plans/applies, causes team conflicts. Fix: Split state by environment, component, region. (3) Manual state editing: Corrupts state structure. Fix: Use terraform state commands. (4) No remote backend: Local .tfstate files risk data loss, prevent collaboration. Fix: Use S3 + DynamoDB, Azure Storage, Terraform Cloud. (5) Hardcoded values: ARNs, regions, CIDRs create inflexible code. Fix: Pass as input variables. (6) Committing secrets: Hardcoding credentials in config makes environment-specific management difficult. Fix: Use external secret stores (Vault, AWS Secrets Manager). (7) No version constraints: Causes reproducibility issues. Fix: Pin terraform and provider versions. (8) Testing gaps: Skipping terraform validate, terraform plan in CI/CD leaves room for regressions. Fix: Automated testing with Terratest. (9) Out-of-band changes: Making changes via cloud console causes configuration drift. Fix: All changes through Terraform. (10) No state locking: Concurrent modifications risk corruption. Fix: Use locking backend. (11) Overusing provisioners: Cannot predict outcomes, increases operational risk. Fix: Prefer cloud-init, user-data, custom AMIs. (12) Complex for_each/dynamic blocks: Hard to read and maintain. Fix: Keep logic simple, use comments. Warning: Terraform makes it easy to start but considerably more challenging to get right. Teams discover this after accumulating significant technical debt. Simple deployments become maintenance nightmares when overlooking best practices.

99% confidence