Toolmingo
Guides16 min read

50 Terraform Interview Questions (With Answers)

Top Terraform interview questions with clear answers and examples — covering HCL syntax, state management, modules, providers, workspaces, and production IaC patterns.

Terraform interviews test your understanding of infrastructure as code, HCL syntax, state management, modules, providers, workspaces, and production patterns. This guide covers the 50 most common questions — with concise answers and real examples.

Quick Reference

Topic Key Concepts
Core providers, resources, data sources, variables, outputs
State terraform.tfstate, remote backend, locking
Modules reusable code, source, input/output variables
Workflow initplanapplydestroy
Workspaces isolated state environments in the same config
Meta-arguments count, for_each, depends_on, lifecycle

Core Concepts

1. What is Terraform and what problem does it solve?

Terraform is an open-source Infrastructure as Code (IaC) tool by HashiCorp. It lets you define cloud infrastructure in human-readable HCL (HashiCorp Configuration Language) files and manage its full lifecycle — create, update, destroy — across multiple providers.

Problems it solves:

  • Manual, error-prone cloud console clicks → reproducible code
  • Inconsistent environments → idempotent configuration
  • No audit trail → version-controlled infrastructure
  • Vendor lock-in → multi-cloud with a single tool

2. What is HCL?

HCL (HashiCorp Configuration Language) is the declarative language used to write Terraform configurations. It's designed to be human-readable and supports strings, numbers, booleans, lists, maps, and expressions.

resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"

  tags = {
    Name = "web-server"
    Env  = var.environment
  }
}

3. What is a Terraform provider?

A provider is a plugin that lets Terraform manage resources for a specific platform (AWS, Azure, GCP, GitHub, Kubernetes, etc.). Providers must be declared in the configuration and downloaded via terraform init.

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

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

4. What is a Terraform resource?

A resource is the most important element in Terraform — it represents a single infrastructure object (VM, bucket, DNS record, etc.). The syntax is resource "<TYPE>" "<NAME>".

resource "aws_s3_bucket" "logs" {
  bucket = "my-app-logs-2025"
}

5. What is a data source?

A data source lets you read existing infrastructure that wasn't created by your current Terraform config. Use it to reference resources managed elsewhere.

data "aws_ami" "ubuntu" {
  most_recent = true
  owners      = ["099720109477"] # Canonical

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-*-22.04-amd64-server-*"]
  }
}

resource "aws_instance" "web" {
  ami = data.aws_ami.ubuntu.id
  # ...
}

6. What are Terraform variables?

Variables make configurations reusable. Types: string, number, bool, list, map, object, tuple, set.

variable "instance_type" {
  type        = string
  description = "EC2 instance type"
  default     = "t3.micro"
}

# Usage
resource "aws_instance" "web" {
  instance_type = var.instance_type
}

Passing values: CLI (-var), .tfvars file, environment variables (TF_VAR_instance_type).

7. What are outputs?

Outputs expose values after apply — useful for passing data between modules or displaying information to users.

output "instance_ip" {
  description = "Public IP of the web instance"
  value       = aws_instance.web.public_ip
}

8. Explain the Terraform workflow.

Command Description
terraform init Download providers and modules, initialise backend
terraform validate Check syntax without contacting providers
terraform fmt Format code to canonical style
terraform plan Preview changes (diff)
terraform apply Apply changes to real infrastructure
terraform destroy Destroy all managed resources
terraform output Show output values
terraform show Show current state or a plan file
terraform import Bring existing resource under Terraform management
terraform taint (deprecated) → terraform apply -replace Force recreation of a resource

State Management

9. What is Terraform state?

State is a JSON file (terraform.tfstate) that maps your Terraform configuration to real-world infrastructure. Terraform uses state to:

  • Track which resources it manages
  • Determine what changes are needed (plan diff)
  • Store metadata (resource IDs, dependencies)

Default location: local terraform.tfstate file.
Production: always use a remote backend with state locking.

10. What is a remote backend and why use one?

A remote backend stores state in a shared, persistent location instead of the local filesystem.

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

Why remote?

  • Team collaboration — everyone reads the same state
  • State locking — prevents concurrent applies
  • Versioning and encryption — auditability and security

Common backends: S3+DynamoDB (AWS), GCS (GCP), Azure Blob, Terraform Cloud/Enterprise.

11. What is state locking?

State locking prevents two operations from modifying state simultaneously, which would corrupt it. With the S3 backend, DynamoDB provides locking. Terraform Cloud locks automatically.

If a lock is stuck (e.g., after a crash): terraform force-unlock <LOCK_ID>.

12. What is terraform.tfstate.backup?

Terraform creates a .backup file before each state write as a safeguard. It contains the previous version of state.

13. What is terraform state and common sub-commands?

The terraform state command lets you inspect and manipulate state directly.

Command Description
terraform state list List all resources in state
terraform state show <resource> Show attributes of a resource
terraform state mv Move/rename a resource in state
terraform state rm Remove a resource from state (without destroying it)
terraform state pull Download and print remote state
terraform state push Upload local state to remote backend

14. What does terraform import do?

terraform import brings an existing (manually created) resource under Terraform management by adding it to state. You still need to write the HCL resource block manually.

# Import existing EC2 instance
terraform import aws_instance.web i-1234567890abcdef0

15. What is the difference between terraform plan -out and terraform apply?

terraform plan -out=tfplan saves the plan to a binary file. terraform apply tfplan applies exactly that saved plan — no interactive confirmation, no drift recalculation. This is the recommended pattern for CI/CD pipelines.


Modules

16. What is a Terraform module?

A module is a container for multiple resources used together. Every Terraform config is technically a module (the root module). Child modules are reusable code called from the root or other modules.

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "5.1.2"

  name = "my-vpc"
  cidr = "10.0.0.0/16"

  azs             = ["us-east-1a", "us-east-1b"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24"]
}

17. What are module sources?

Source Example
Local path source = "./modules/vpc"
Terraform Registry source = "hashicorp/consul/aws"
GitHub source = "github.com/org/repo"
S3 bucket source = "s3::https://..."
Git URL source = "git::https://..."

18. How do you pass data in and out of a module?

  • Input: declare variable blocks inside the module, pass values from module block
  • Output: declare output blocks inside the module, reference as module.<NAME>.<OUTPUT>
# modules/ec2/main.tf
variable "instance_type" {}
output "public_ip" { value = aws_instance.this.public_ip }

# root/main.tf
module "web" {
  source        = "./modules/ec2"
  instance_type = "t3.small"
}
output "web_ip" { value = module.web.public_ip }

19. What is the Terraform Registry?

The public registry at registry.terraform.io hosts community and HashiCorp-verified providers and modules. You can also use a private registry (Terraform Cloud/Enterprise).

20. Why should you pin module and provider versions?

Without version pinning, terraform init fetches the latest version, which can introduce breaking changes. Always pin:

terraform {
  required_providers {
    aws = { source = "hashicorp/aws", version = "~> 5.0" }
  }
  required_version = ">= 1.6"
}

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "5.1.2"
}

Meta-Arguments

21. What is count?

count creates multiple instances of a resource. Access each with <resource>[index].

resource "aws_instance" "web" {
  count         = 3
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"
  tags = { Name = "web-${count.index}" }
}

22. What is for_each?

for_each creates instances from a map or set. Preferred over count when resources have distinct identities — avoids index-shift problems.

variable "buckets" {
  default = { logs = "eu-west-1", backups = "us-east-1" }
}

resource "aws_s3_bucket" "this" {
  for_each = var.buckets
  bucket   = "myapp-${each.key}"
  # each.key = "logs", each.value = "eu-west-1"
}

23. When to use count vs for_each?

count for_each
Input type integer map or set of strings
Reference resource[0], resource[1] resource["key"]
Deletion risk Re-index shifts resources Only the keyed resource affected
Best for identical resources resources with distinct names/configs

24. What is depends_on?

Terraform infers most dependencies automatically from references. depends_on is for hidden dependencies not expressed through references (e.g., IAM policy must be attached before an EC2 instance profile is used).

resource "aws_instance" "app" {
  # ...
  depends_on = [aws_iam_role_policy_attachment.this]
}

25. What is the lifecycle block?

lifecycle customises resource behaviour:

resource "aws_instance" "web" {
  # ...
  lifecycle {
    create_before_destroy = true   # zero-downtime replacement
    prevent_destroy       = true   # block accidental destroy
    ignore_changes        = [tags] # ignore drift on these attrs
    replace_triggered_by  = [aws_ami.this.id] # re-create on AMI change
  }
}

Workspaces

26. What are Terraform workspaces?

Workspaces allow multiple isolated state files within the same configuration directory. Each workspace has its own terraform.tfstate.

terraform workspace new staging
terraform workspace select prod
terraform workspace list

Use terraform.workspace in code to branch logic:

locals {
  instance_type = terraform.workspace == "prod" ? "t3.large" : "t3.micro"
}

27. What are the limitations of workspaces?

  • All workspaces share the same backend configuration
  • Not ideal for fundamentally different infrastructure (use separate root modules instead)
  • Terraform Cloud workspaces are richer than CLI workspaces (different repos, different vars, VCS-driven runs)

Expressions and Functions

28. What are locals?

locals are computed values that avoid repetition. Unlike variables, they cannot be set from outside.

locals {
  name_prefix = "${var.project}-${var.environment}"
  common_tags = {
    Project     = var.project
    Environment = var.environment
    ManagedBy   = "Terraform"
  }
}

resource "aws_vpc" "main" {
  tags = merge(local.common_tags, { Name = "${local.name_prefix}-vpc" })
}

29. What are commonly used Terraform built-in functions?

Category Functions
String format, join, split, replace, trimspace, lower, upper
Collection length, merge, concat, flatten, toset, tolist, tomap, lookup, keys, values
Numeric max, min, ceil, floor, abs
Encoding jsonencode, jsondecode, base64encode, base64decode
Filesystem file, templatefile
IP network cidrsubnet, cidrhost
Type tostring, tonumber, tobool

30. What is a dynamic block?

dynamic generates repeated nested blocks (e.g., security group ingress rules) from a collection.

variable "ingress_rules" {
  default = [
    { port = 80,  cidr = "0.0.0.0/0" },
    { port = 443, cidr = "0.0.0.0/0" },
  ]
}

resource "aws_security_group" "web" {
  dynamic "ingress" {
    for_each = var.ingress_rules
    content {
      from_port   = ingress.value.port
      to_port     = ingress.value.port
      protocol    = "tcp"
      cidr_blocks = [ingress.value.cidr]
    }
  }
}

31. What is templatefile?

templatefile renders a template file with given variables — useful for user-data scripts.

resource "aws_instance" "web" {
  user_data = templatefile("${path.module}/user_data.sh.tpl", {
    db_host = aws_db_instance.main.address
    app_env = var.environment
  })
}

32. What are conditional expressions?

# condition ? true_val : false_val
instance_type = var.environment == "prod" ? "t3.large" : "t3.micro"

# Conditional resource creation with count
resource "aws_eip" "nat" {
  count = var.enable_nat ? 1 : 0
}

Security and Best Practices

33. How do you manage secrets in Terraform?

Never hardcode secrets. Options:

Method How
Environment variables TF_VAR_db_password=...
.tfvars file (gitignored) db_password = "..."
AWS Secrets Manager data source data "aws_secretsmanager_secret_version"
HashiCorp Vault provider data "vault_generic_secret"
Terraform Cloud variables Sensitive variable marked "sensitive"

Mark sensitive outputs to prevent display:

output "db_password" {
  value     = random_password.db.result
  sensitive = true
}

34. What is sensitive = true in variables?

Marking a variable sensitive prevents its value from appearing in plan/apply output and logs.

variable "db_password" {
  type      = string
  sensitive = true
}

35. How do you prevent accidental resource deletion?

  1. lifecycle { prevent_destroy = true } in the resource block
  2. Terraform Cloud policy-as-code (Sentinel / OPA)
  3. IAM policies that restrict the deploying principal

Advanced Topics

36. What is terraform refresh / -refresh-only?

terraform refresh (deprecated in favour of terraform apply -refresh-only) updates state to match real-world infrastructure without making changes. Useful for detecting drift.

terraform apply -refresh-only

37. What is drift?

Drift occurs when real infrastructure diverges from the Terraform state (e.g., someone manually changed an EC2 instance type via the console). terraform plan detects drift and shows what changes would bring infrastructure back to the desired state.

38. What is terraform taint / -replace?

Forces recreation of a specific resource on next apply. Since Terraform 0.15.2, preferred syntax:

terraform apply -replace="aws_instance.web"

39. What is terraform graph?

Outputs a DOT-format dependency graph of the current config. Visualise with Graphviz:

terraform graph | dot -Tsvg > graph.svg

40. What is the .terraform.lock.hcl file?

The dependency lock file records the exact provider versions and checksums used by terraform init. Commit this to version control so all team members and CI use identical provider versions.

41. What are Terraform provisioners?

Provisioners run local or remote scripts on resources after creation. They are a last resort — prefer cloud-native init mechanisms (EC2 user-data, Azure custom script extension, etc.).

resource "aws_instance" "web" {
  # ...
  provisioner "remote-exec" {
    inline = ["sudo apt-get install -y nginx"]
    connection {
      type        = "ssh"
      user        = "ubuntu"
      private_key = file("~/.ssh/id_rsa")
      host        = self.public_ip
    }
  }
}

Problems with provisioners: failures leave resources in unknown state; not idempotent; violate immutable infrastructure principle.

42. What is a null resource and when would you use it?

null_resource has no infrastructure representation but can run provisioners or act as a dependency anchor. Replaced in modern Terraform by terraform_data (v1.4+).

resource "null_resource" "run_script" {
  triggers = { always = timestamp() }
  provisioner "local-exec" { command = "echo done" }
}

43. What is moved block?

The moved block tells Terraform that a resource was renamed/moved, so it updates state without destroying and recreating.

moved {
  from = aws_instance.old_name
  to   = aws_instance.new_name
}

44. What is Terraform Cloud vs Terraform Enterprise?

Terraform Cloud Terraform Enterprise
Hosting SaaS (HashiCorp) Self-hosted
Pricing Free tier + paid plans License fee
Features Remote runs, state, registry, Sentinel All Cloud features + SSO, audit, clustering
Best for Teams without infra restrictions Regulated enterprises

CI/CD and Workflows

45. How do you use Terraform in a CI/CD pipeline?

Recommended pattern:

# GitHub Actions example
jobs:
  terraform:
    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-terraform@v3
      - run: terraform init
      - run: terraform validate
      - run: terraform plan -out=tfplan
      - run: terraform apply -auto-approve tfplan
        if: github.ref == 'refs/heads/main'

Key practices:

  • Store state in remote backend (not the runner)
  • Use OIDC / short-lived credentials (no long-lived AWS keys in CI)
  • Plan on PR, apply on merge to main
  • Post plan output as PR comment

46. What is the Atlantis pattern?

Atlantis is an open-source tool that runs terraform plan on PRs and terraform apply when you comment atlantis apply. It keeps apply tied to reviewed, merged code without giving CI broad permissions.

47. Describe a blue-green deployment with Terraform.

# Create new (green) before destroying old (blue)
resource "aws_autoscaling_group" "app" {
  lifecycle { create_before_destroy = true }
}

# Shift traffic via ALB target group weight
resource "aws_lb_listener_rule" "blue_green" {
  # forward to green TG at 100% after validation
}

Comparison

48. Terraform vs CloudFormation vs Pulumi

Feature Terraform CloudFormation Pulumi
Language HCL JSON/YAML Python, TS, Go, C#
Multi-cloud Yes (1000+ providers) AWS only Yes
State management Self-managed or TF Cloud AWS-managed Self or Pulumi Cloud
Import existing terraform import CloudFormation import pulumi import
Drift detection terraform plan Stack drift detection pulumi preview
Community modules Terraform Registry No equivalent Pulumi Registry
Maturity Very high Very high Growing
Best for Multi-cloud IaC AWS-only teams Devs preferring real languages

49. Terraform vs Ansible

Terraform Ansible
Primary use Infrastructure provisioning Configuration management
State Stateful Stateless (idempotent plays)
Language HCL declarative YAML imperative/procedural
Cloud resources Native Via modules (less first-class)
OS config Limited Excellent
Combined use Terraform provisions → Ansible configures

50. Common Terraform Anti-Patterns

Anti-pattern Problem Fix
Local state in team environment Conflicts, no locking Remote backend + locking
terraform apply in CI without saved plan Plan may differ from what was reviewed plan -out, then apply tfplan
Giant root module (all infra in one file) Blast radius, slow plans Split into environments + modules
Hardcoded secrets Security exposure Secrets manager data sources
Unpinned provider versions Breaking changes on init version = "~> 5.0" constraint
count for named resources Index shift deletes the wrong resource for_each with meaningful keys
Manual console changes Drift, conflicts on next apply Enforce IaC-only changes via SCPs
No state backup/versioning Unrecoverable state corruption S3 versioning + DynamoDB lock

Common Mistakes

Mistake What Happens Fix
Deleting a resource block without state rm Terraform destroys the resource terraform state rm first if not destroying
Running apply without plan review Unexpected changes deployed Always review plan, use -out in CI
Using terraform.workspace for env isolation alone Shared backend can confuse Use separate backends or directories per env
Forgetting terraform init after adding provider "Provider not found" error Always init after config changes
Modifying state manually State corruption Use terraform state sub-commands
for_each with a list (not a set/map) Type error Convert: for_each = toset(var.list)
Circular dependencies Error: cycle Refactor using depends_on or restructure resources
Large blast radius in single workspace One mistake destroys everything Split by environment and service

Terraform vs Related Tools

Tool Category Relation to Terraform
Ansible Config mgmt Complementary — Terraform provisions, Ansible configures
CloudFormation IaC AWS-only alternative
Pulumi IaC Alternative with real programming languages
AWS CDK IaC AWS-only, code-first (TS/Python/Java)
Terragrunt Terraform wrapper Adds DRY config, remote state helpers
Atlantis GitOps for Terraform Automates plan/apply via PR comments
Checkov / tfsec Security scanner Scans HCL for misconfigurations
Infracost Cost estimation Shows terraform plan cost impact

FAQ

Q: How does Terraform know which resources to update?
A: It computes a diff between desired state (your HCL) and current state (tfstate). Only resources with differences are touched.

Q: Can Terraform manage resources it didn't create?
A: Yes — use terraform import to bring existing resources into state, then write the matching HCL block.

Q: What happens if two people run terraform apply simultaneously?
A: With a remote backend + locking (DynamoDB or Terraform Cloud), the second operation waits or errors with "state locked". Without locking, state corruption is possible.

Q: What is the difference between terraform destroy and removing all resource blocks?
A: Both destroy resources, but terraform destroy is explicit and safer. Removing resource blocks and running apply has the same effect but is less obvious to reviewers.

Q: How do you handle multi-region or multi-account deployments?
A: Use provider aliases for multi-region, and assume_role in the AWS provider for cross-account. Each environment gets its own remote state key/path.

provider "aws" { alias = "eu"; region = "eu-west-1" }
resource "aws_s3_bucket" "eu_logs" {
  provider = aws.eu
  bucket   = "my-eu-logs"
}

Q: What is Sentinel in Terraform?
A: Sentinel is HashiCorp's policy-as-code framework (Terraform Cloud/Enterprise). It lets you write policies that block apply if infrastructure doesn't meet compliance rules (e.g., all S3 buckets must have encryption, no public EC2 instances).

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools