50 Terraform Interview Questions and Answers (Beginner to Advanced) – 2026 Guide

Gone are the days when knowing basic HCL syntax was enough. In 2026, interviewers expect you to understand state management intricacies, module design patterns, and how to handle multi-cloud deployments without breaking a sweat.

This guide covers 50 real Terraform interview questions which are been asked frequently in the IT industry. They’re organized from beginner to advanced, so whether you’re applying for your first DevOps role or a senior infrastructure position, you’ll find questions at your level.

Let’s dive in.

How to Use This Guide

I’ve structured this guide into three sections based on experience level. If you’re preparing for an interview, I recommend:

  • Beginners (0-1 year Terraform): Master the first 20 questions thoroughly before moving on
  • Intermediate (1-3 years): Focus on questions 21-40, but review beginners for interview warmups
  • Advanced (3+ years): All questions are fair game, especially 41-50 which test architectural thinking

Don’t just memorize answers. Understand the “why” behind each one, because good interviewers will ask follow-up questions.

Beginner Level Questions (1-20)

50 Terraform Interview Questions and Answers

These questions test fundamental Terraform knowledge. If you’re new to infrastructure-as-code, spend extra time here.

1. What is Terraform and why would you use it over manual infrastructure management?

Answer: Terraform is an infrastructure-as-code tool that lets you define and provision infrastructure using declarative configuration files. Instead of clicking through AWS console or running CLI commands manually, you write what infrastructure you want, and Terraform figures out how to create it.

Why use it? Four main reasons from my experience: infrastructure becomes version-controlled (you can track changes in Git), it’s reproducible (spin up identical environments easily), you get automation (no manual clicking), and it provides consistency (everyone uses the same configurations).

Follow-up tip: Be ready to explain a specific scenario where you used Terraform to solve a problem, like “We needed to spin up identical staging environments for each developer, which would’ve taken hours manually.”

2. Explain the difference between Terraform and other IaC tools like CloudFormation or Ansible.

Answer: The key difference is scope and approach. Terraform is cloud-agnostic and uses declarative syntax, meaning you describe the end state you want. CloudFormation is AWS-specific, also declarative. Ansible is configuration management focused, uses imperative syntax (step-by-step instructions), and is better suited for software installation and configuration rather than infrastructure provisioning.

In practice, I’ve used Terraform to provision infrastructure (VPCs, EC2 instances, databases) and then Ansible to configure the software on those instances. They complement each other.

3. What are Terraform providers?

Answer: Providers are plugins that let Terraform interact with cloud platforms, SaaS providers, or other APIs. Think of them as translators between your Terraform code and the actual service APIs.

Common providers include AWS, Azure, GCP, Kubernetes, and Datadog. You declare them in your configuration:

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

provider "kubernetes" {
  config_path = "~/.kube/config"
}

Each provider has its own authentication method and resource types.

4. What is the Terraform workflow (write, plan, apply)?

Answer: The standard Terraform workflow has three stages:

  1. Write: Create .tf files defining your desired infrastructure
  2. Plan: Run terraform plan to preview changes before applying them
  3. Apply: Run terraform apply to actually create/modify infrastructure

The plan step is crucial—it shows you exactly what will be created, modified, or destroyed before you commit. I always review plans carefully, especially the destroy operations marked in red.

5. What is Terraform state and why is it important?

Answer: The state file (terraform.tfstate) is Terraform’s database of your infrastructure. It maps your configuration to real-world resources and tracks metadata. When you run plan or apply, Terraform compares your configuration to the state to determine what changes need to be made.

Why it’s critical: without state, Terraform has no idea what infrastructure already exists. You’d end up trying to create resources that already exist, causing errors. The state file contains sensitive information, so never commit it to Git—use remote backends like S3 instead.

6. What’s the difference between terraform plan and terraform apply?

Answer: terraform plan is a dry-run that shows you what changes will be made without actually making them. It’s safe to run anytime. terraform apply actually executes those changes and modifies your real infrastructure.

Best practice from painful experience: always run plan first, review the output carefully, and only then run apply. I’ve seen people skip the plan step and accidentally destroy production resources.

7. How do you initialize a Terraform working directory?

Answer: Use terraform init. This command:

  • Downloads required provider plugins
  • Sets up the backend for state storage
  • Downloads modules referenced in your configuration
  • Creates a .terraform directory with all dependencies

You need to run this whenever you start working with a new Terraform configuration or when you add new providers/modules.

8. What are Terraform variables and how do you define them?

Answer: Variables let you parameterize your Terraform configurations, making them reusable across environments. You define them using variable blocks:

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

variable "environment" {
  description = "Environment name"
  type        = string
}

You can pass values through command line (-var), variable files (terraform.tfvars), or environment variables (TF_VAR_name).

9. What’s the difference between variables and locals in Terraform?

Answer: Variables are inputs to your module that users can customize. Locals are computed values used internally within your module that users can’t override.

Use variables when you want flexibility (like instance type or region). Use locals for derived values or constants you don’t want users changing:

locals {
  common_tags = {
    Environment = var.environment
    ManagedBy   = "Terraform"
    Timestamp   = timestamp()
  }
}

10. How do you output values from Terraform?

Answer: Use output blocks to export values after infrastructure is created. This is useful for getting resource IDs, IP addresses, or other computed values:

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

output "database_endpoint" {
  description = "RDS endpoint"
  value       = aws_db_instance.main.endpoint
  sensitive   = true
}

Outputs appear after apply completes and can be queried later with terraform output. Use sensitive = true for passwords or keys.

11. What are Terraform modules and why use them?

Answer: Modules are containers for multiple resources that are used together. Think of them as reusable blueprints. Instead of copying the same 50 lines of code to create a VPC in every project, you create a VPC module once and reuse it.

Benefits from real projects: code reuse (DRY principle), standardization across teams, easier testing, and better organization. A typical structure might have modules for networking, compute, and database layers.

12. How do you use a Terraform module?

Answer: You call modules using a module block:

module "vpc" {
  source = "./modules/vpc"
  
  vpc_cidr    = "10.0.0.0/16"
  environment = "production"
  az_count    = 3
}

The source can be a local path, Git repository, Terraform Registry, or S3 bucket. After adding a module, run terraform init to download it.

13. What is terraform.tfstate file and should it be committed to Git?

Answer: Absolutely NOT. The state file contains sensitive data like passwords, private keys, and complete resource configurations. Committing it to Git is a security risk.

Instead, use remote backends like S3 with encryption and DynamoDB for state locking. Add terraform.tfstate to your .gitignore file. I’ve seen companies expose database credentials because someone committed state files to public repos.

14. What are Terraform backends and why use them?

Answer: Backends determine where Terraform stores its state. The default backend is local (stores state on your machine), but this doesn’t work for teams.

Remote backends like S3, Azure Blob Storage, or Terraform Cloud provide:

  • Shared state access for team collaboration
  • State locking to prevent concurrent modifications
  • Encryption at rest
  • State history and versioning
terraform {
  backend "s3" {
    bucket         = "my-terraform-state"
    key            = "prod/terraform.tfstate"
    region         = "us-east-1"
    encrypt        = true
    dynamodb_table = "terraform-locks"
  }
}

15. What is state locking and why is it important?

Answer: State locking prevents multiple users from running Terraform operations simultaneously, which could corrupt the state file. When you run apply, Terraform acquires a lock. If someone else tries to run apply at the same time, they’ll get an error until the lock is released.

For S3 backends, you use DynamoDB for locking. Without it, two engineers could both try to create the same resource, causing conflicts and potentially broken infrastructure.

16. How do you handle sensitive data in Terraform?

Answer: Several approaches based on what I’ve implemented:

  1. Mark outputs as sensitive: Prevents them from appearing in console output
  2. Use environment variables: TF_VAR_db_password instead of hardcoding
  3. External secret management: AWS Secrets Manager, Vault, or parameter stores
  4. Encrypt state files: Enable encryption on remote backends
  5. Never hardcode secrets: No passwords in .tf files, ever
data "aws_secretsmanager_secret_version" "db_password" {
  secret_id = "prod/db/password"
}

resource "aws_db_instance" "main" {
  password = data.aws_secretsmanager_secret_version.db_password.secret_string
}

17. What is the purpose of terraform destroy?

Answer: terraform destroy tears down all infrastructure managed by your configuration. It’s useful for cleaning up dev/test environments or decommissioning projects.

Pro tip: use it carefully. I always run terraform plan -destroy first to see what will be deleted. For production, consider using lifecycle prevent_destroy on critical resources to add a safety net.

18. What are Terraform data sources?

Answer: Data sources let you fetch information from existing resources without managing them. You’re querying, not creating.

Example: fetching the latest Amazon Linux AMI instead of hardcoding an AMI ID that becomes outdated:

data "aws_ami" "amazon_linux" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["amzn2-ami-hvm-*-x86_64-gp2"]
  }
}

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

19. What is the difference between count and for_each?

Answer: Both create multiple instances of a resource, but for_each is more flexible and safer.

count uses numeric indices (0, 1, 2). If you remove an item from the middle of your list, Terraform recreates everything after it.

for_each uses keys (strings or sets), so removing an item only affects that specific resource.

# Count - fragile
resource "aws_instance" "server" {
  count = 3
  # referenced as aws_instance.server[0]
}

# for_each - better
resource "aws_instance" "server" {
  for_each = toset(["web", "api", "worker"])
  # referenced as aws_instance.server["web"]
}

Use for_each unless you need a simple numeric count.

20. How do you manage multiple environments (dev, staging, prod) with Terraform?

Answer: Three common approaches, each with trade-offs:

1. Separate directories: Duplicate code in dev/, staging/, prod/ folders. Simple but violates DRY.

2. Workspaces: Use terraform workspace to switch between environments using the same code. Good for small differences.

3. Variable files: One codebase, different .tfvars files (dev.tfvars, prod.tfvars). This is what I prefer for most projects:

# dev.tfvars
environment = "dev"
instance_type = "t3.micro"

# prod.tfvars
environment = "prod"
instance_type = "t3.large"

# Deploy with:
terraform apply -var-file="prod.tfvars"

Intermediate Level Questions (21-40)

Intermediate Level Questions (21-40)

These questions test deeper understanding of Terraform operations, state management, and best practices.

21. Explain Terraform’s resource lifecycle and the lifecycle meta-argument.

Answer: The lifecycle block controls how Terraform handles resource creation and destruction. Key options:

resource "aws_instance" "web" {
  # ... configuration ...

  lifecycle {
    create_before_destroy = true  # Create new before destroying old
    prevent_destroy       = true  # Block accidental destruction
    ignore_changes        = [tags] # Don't update if these change
  }
}

Real example: I use prevent_destroy on production databases to prevent accidental deletion. One terraform destroy command could wipe out customer data without this safeguard.

22. What is terraform taint and when would you use it?

Answer: Note: terraform taint is deprecated in Terraform 0.15.2+. The modern approach is terraform apply -replace.

This marks a resource for recreation on the next apply. Use cases from my experience:

  • An EC2 instance is corrupted but Terraform thinks it’s fine
  • You need to force a database failover
  • Manual changes were made that need to be reset
# Old way (deprecated)
terraform taint aws_instance.web

# New way
terraform apply -replace="aws_instance.web"

23. How do you import existing infrastructure into Terraform?

Answer: Use terraform import to bring existing resources under Terraform management. Two-step process:

  1. Write the resource configuration block (without creating it)
  2. Import the existing resource into state
# Step 1: Write config
resource "aws_instance" "existing" {
  # ... configuration matching existing instance ...
}

# Step 2: Import
terraform import aws_instance.existing i-1234567890abcdef0

After import, run terraform plan to verify no changes are needed. Adjust your config until plan shows no changes.

24. What are Terraform workspaces and when should you use them?

Answer: Workspaces let you maintain multiple state files for the same configuration. Think of them as parallel universes for your infrastructure.

terraform workspace new dev
terraform workspace new staging
terraform workspace select prod
terraform workspace list

When to use: Multiple similar environments (dev/staging/prod) with small differences. The workspace name is available as terraform.workspace in your code.

When NOT to use: Completely different infrastructure setups, multi-region deployments, or when you need strict separation. For those, use separate state files and directories.

25. Explain Terraform provisioners and why they’re generally discouraged.

Answer: Provisioners run scripts on resources after creation (like remote-exec, local-exec). They’re considered a last resort because:

  • They break Terraform’s declarative model
  • Failures aren’t handled gracefully
  • They can’t be properly tracked in state
  • Configuration management tools do this better

Better alternatives: Use user_data for EC2 startup scripts, cloud-init, or proper config management like Ansible. Only use provisioners when absolutely necessary, like bootstrapping a config management tool.

26. How do you handle Terraform state file corruption or loss?

Answer: This is a nightmare scenario I’ve dealt with twice. Recovery strategies:

Prevention (best approach):

  • Use remote backends with versioning (S3 with versioning enabled)
  • Regular state backups
  • State locking to prevent concurrent modifications

Recovery if state is lost:

  • Restore from backend version history
  • Use terraform import for each resource (tedious but works)
  • Use terraform state pull/push if you have an old backup
# Pull old version from S3
aws s3api list-object-versions --bucket my-terraform-state

# Restore specific version
aws s3api get-object --bucket my-terraform-state \
  --key terraform.tfstate --version-id [VERSION_ID] \
  terraform.tfstate

27. What is terraform refresh and when do you use it?

Answer: terraform refresh updates the state file to match the real-world infrastructure without modifying resources. It’s now integrated into plan and apply by default.

Use cases: someone made manual changes in the console and you want to sync the state, or you’re troubleshooting state drift. However, it’s better to run terraform plan -refresh-only to see what would change before updating state.

28. How do you manage dependencies between resources in Terraform?

Answer: Terraform automatically handles most dependencies through resource references. When you use one resource’s output as another’s input, Terraform figures out the order:

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
}

resource "aws_subnet" "public" {
  vpc_id = aws_vpc.main.id  # Implicit dependency
}

For explicit dependencies that aren’t obvious from references:

resource "aws_instance" "web" {
  # ... config ...
  
  depends_on = [
    aws_security_group.allow_http,
    aws_iam_role_policy.s3_access
  ]
}

29. What are dynamic blocks in Terraform and when would you use them?

Answer: Dynamic blocks generate repeated nested blocks based on lists or maps. They’re perfect when you have variable numbers of similar configurations:

resource "aws_security_group" "web" {
  name = "web-sg"

  dynamic "ingress" {
    for_each = var.ingress_rules
    content {
      from_port   = ingress.value.from_port
      to_port     = ingress.value.to_port
      protocol    = ingress.value.protocol
      cidr_blocks = ingress.value.cidr_blocks
    }
  }
}

Real example: I used this for security groups where different environments needed different port rules. Instead of duplicating code, one dynamic block handled all cases.

30. How do you handle secrets in Terraform modules?

Answer: Never pass secrets as plain text variables. Better approaches:

  1. Data sources from secret stores:
data "aws_secretsmanager_secret_version" "api_key" {
  secret_id = "prod/api/key"
}

module "app" {
  source  = "./modules/app"
  api_key = data.aws_secretsmanager_secret_version.api_key.secret_string
}
  1. Mark variable as sensitive:
variable "db_password" {
  type      = string
  sensitive = true
}
  1. Use external secret management: HashiCorp Vault, AWS Secrets Manager, Azure Key Vault

31. What is the terraform graph command used for?

Answer: terraform graph generates a visual representation of your configuration’s resource dependencies in DOT format. Pipe it to graphviz to create an actual diagram:

terraform graph | dot -Tpng > graph.png

It’s incredibly useful for:

  • Understanding complex module dependencies
  • Debugging circular dependencies
  • Documentation for new team members
  • Explaining infrastructure relationships to non-technical stakeholders

32. How do you manage Terraform version constraints?

Answer: Use required_version to specify Terraform version and required_providers for provider versions:

terraform {
  required_version = ">= 1.5.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
    kubernetes = {
      source  = "hashicorp/kubernetes"
      version = ">= 2.20.0, < 3.0.0"
    }
  }
}

Version constraint operators:

  • = 1.5.0 – Exact version
  • >= 1.5.0 – Greater than or equal
  • ~> 1.5.0 – Any 1.5.x version (pessimistic constraint)
  • >= 1.5, < 2.0 – Range

33. What is state locking with DynamoDB and how does it work?

Answer: When using S3 backend, DynamoDB provides state locking. Here’s the setup:

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

How it works: Terraform creates a record in DynamoDB when acquiring a lock. If another operation tries to run, it sees the lock and waits. When the first operation completes, the lock is released.

The DynamoDB table needs a primary key called LockID (string). That’s it—Terraform handles the rest.

34. How do you organize a large Terraform project?

Answer: After managing projects with 100+ resources, here’s what works:

project/
├── modules/
│   ├── networking/
│   ├── compute/
│   └── database/
├── environments/
│   ├── dev/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   └── terraform.tfvars
│   ├── staging/
│   └── prod/
├── global/
│   └── iam/
└── scripts/

Best practices I follow:

  • Split by layer (networking, compute, data) not by environment
  • Keep modules small and focused (single responsibility)
  • Use remote state data sources to reference outputs between layers
  • Separate backend configurations per environment
  • Never nest modules more than 2 levels deep

35. What are null_resource and terraform_data, and when would you use them?

Answer: These are special resources that don’t create actual infrastructure. terraform_data (introduced in Terraform 1.4) replaces null_resource.

Use cases:

  • Running local scripts as part of Terraform workflow
  • Creating dependencies between resources
  • Triggering actions when certain values change
resource "terraform_data" "example" {
  triggers_replace = {
    always_run = timestamp()
  }

  provisioner "local-exec" {
    command = "echo 'Infrastructure updated'"
  }
}

36. How do you handle Terraform state migrations?

Answer: State migrations happen when changing backend configurations. Steps I follow:

  1. Backup current state: terraform state pull > backup.tfstate
  2. Update backend configuration in your code
  3. Run terraform init -migrate-state
  4. Verify migration: terraform plan should show no changes
  5. Delete local state files once confirmed

Example: migrating from local to S3:

# Before: no backend block (local state)

# After: add backend
terraform {
  backend "s3" {
    bucket = "my-terraform-state"
    key    = "terraform.tfstate"
    region = "us-east-1"
  }
}

# Then run
terraform init -migrate-state

37. What is the difference between terraform validate and terraform plan?

Answer:

terraform validate:

  • Checks syntax and configuration validity
  • Runs offline (no API calls)
  • Fast and safe
  • Catches typos, missing required arguments, invalid types

terraform plan:

  • Checks what will actually happen
  • Makes API calls to providers
  • Compares desired state with current state
  • Shows create/update/delete operations

In CI/CD pipelines, run validate in the lint stage and plan in the preview stage.

38. How do you reference outputs from one module in another?

Answer: Use module outputs in your calling configuration:

module "networking" {
  source = "./modules/vpc"
  cidr   = "10.0.0.0/16"
}

module "compute" {
  source = "./modules/ec2"
  vpc_id = module.networking.vpc_id  # Reference output from networking module
  subnet_ids = module.networking.private_subnet_ids
}

For completely separate Terraform projects, use remote state data sources:

data "terraform_remote_state" "networking" {
  backend = "s3"
  config = {
    bucket = "terraform-state"
    key    = "networking/terraform.tfstate"
    region = "us-east-1"
  }
}

resource "aws_instance" "web" {
  subnet_id = data.terraform_remote_state.networking.outputs.subnet_id
}

39. What are Terraform functions and give examples of commonly used ones?

Answer: Terraform has built-in functions for manipulating data. You can’t create custom functions, but the built-in ones are powerful:

String functions:

upper("hello")           # "HELLO"
lower("WORLD")           # "world"
format("instance-%s", var.env)  # "instance-prod"
join("-", ["web", "server", "01"]) # "web-server-01"

Collection functions:

length([1, 2, 3])        # 3
merge(map1, map2)        # Combines maps
concat(list1, list2)     # Combines lists
lookup(map, "key", "default")  # Safe map access

Type conversion:

tolist(["a", "b"])       # Converts to list
toset(["a", "a", "b"])   # ["a", "b"] (removes duplicates)
tostring(123)            # "123"

I use these constantly for building resource names, tags, and CIDR calculations.

40. How do you test Terraform code?

Answer: Multiple testing layers based on what I’ve implemented:

1. Validation and linting:

terraform fmt -check    # Format checking
terraform validate      # Syntax validation
tflint                  # Static analysis

2. Unit testing with Terratest:

// Go test that deploys and verifies infrastructure
func TestVPCModule(t *testing.T) {
    terraformOptions := &terraform.Options{
        TerraformDir: "../modules/vpc",
    }
    defer terraform.Destroy(t, terraformOptions)
    terraform.InitAndApply(t, terraformOptions)
    
    vpcID := terraform.Output(t, terraformOptions, "vpc_id")
    assert.NotEmpty(t, vpcID)
}

3. Policy as code:

  • Sentinel (Terraform Cloud/Enterprise)
  • OPA (Open Policy Agent)
  • Checkov for security scanning

4. Integration testing: Deploy to test environment, run smoke tests, destroy.

Advanced Level Questions (41-50)

Advanced Level Questions (41-50)

These questions test architectural decisions, advanced patterns, and production-scale Terraform management.

41. Design a multi-account AWS architecture using Terraform. How do you structure it?

Answer: For organizations with multiple AWS accounts (dev, staging, prod, security, logging), I structure like this:

project/
├── accounts/
│   ├── dev/
│   ├── staging/
│   ├── prod/
│   └── security/
├── modules/
│   ├── account-baseline/  # IAM, CloudTrail, Config
│   ├── networking/        # VPC, Transit Gateway
│   └── compute/
├── org-root/             # AWS Organizations config
└── shared/               # Cross-account resources

Key patterns:

  • Separate state files per account
  • Use AWS provider assume_role for cross-account access
  • Centralized logging account with read-only cross-account roles
  • Use terraform_remote_state for cross-account references
provider "aws" {
  alias  = "prod"
  region = "us-east-1"
  
  assume_role {
    role_arn = "arn:aws:iam::123456789:role/TerraformRole"
  }
}

42. How do you handle Terraform state at scale (1000+ resources)?

Answer: At this scale, monolithic state files become unmanageable. Strategies I’ve used:

1. State splitting by layer:

  • networking.tfstate (VPCs, subnets, route tables)
  • compute.tfstate (EC2, ASGs, load balancers)
  • data.tfstate (RDS, ElastiCache, S3)
  • security.tfstate (IAM, Security Groups)

2. Use targeted applies when possible:

terraform apply -target=module.networking.aws_vpc.main

3. Implement state operations carefully:

  • Use -parallelism flag to control concurrent operations
  • Break deployments into smaller batches
  • Consider Terraform Cloud/Enterprise for better state handling

4. Monitoring: Track state file size, plan/apply durations, and set alerts for unusual growth.

43. Explain how you would implement blue-green deployments with Terraform.

Answer: Blue-green deployments mean running two identical environments and switching traffic between them. Here’s how I implement it:

variable "active_environment" {
  description = "Which environment receives traffic: blue or green"
  type        = string
  default     = "blue"
}

module "blue_environment" {
  source = "./modules/app-environment"
  name   = "blue"
  # ... configuration ...
}

module "green_environment" {
  source = "./modules/app-environment"
  name   = "green"
  # ... configuration ...
}

resource "aws_lb_listener_rule" "routing" {
  listener_arn = aws_lb_listener.main.arn

  action {
    type             = "forward"
    target_group_arn = var.active_environment == "blue" ? 
                       module.blue_environment.target_group_arn : 
                       module.green_environment.target_group_arn
  }
}

Deployment process:

  1. Deploy new version to inactive environment (green)
  2. Test green environment
  3. Switch traffic: terraform apply -var="active_environment=green"
  4. Monitor for issues
  5. Quick rollback if needed by switching back to blue

44. How do you manage Terraform in a CI/CD pipeline?

Answer: Here’s the CI/CD pipeline I’ve implemented with GitHub Actions (similar concepts apply to GitLab, Jenkins, etc.):

Pull Request Stage:

# .github/workflows/terraform-pr.yml
- name: Terraform Format
  run: terraform fmt -check
  
- name: Terraform Validate  
  run: terraform validate

- name: Terraform Plan
  run: terraform plan -out=tfplan
  
- name: Post Plan to PR
  # Comment plan output on PR for review

Merge to Main Stage:

- name: Terraform Apply
  run: terraform apply -auto-approve tfplan
  if: github.ref == 'refs/heads/main'

Key practices:

  • Store state in remote backend, never in CI
  • Use service accounts/roles for authentication, not hardcoded keys
  • Require plan approval before apply in production
  • Run security scanning (Checkov, tfsec) before plan
  • Separate pipelines for different environments
  • Save plan artifacts for compliance/audit trail

45. What strategies do you use for zero-downtime infrastructure updates?

Answer: Several patterns depending on the resource type:

1. create_before_destroy lifecycle:

resource "aws_launch_template" "app" {
  # ... config ...
  
  lifecycle {
    create_before_destroy = true
  }
}

2. Blue-green deployments: As described in question 43

3. Rolling updates with Auto Scaling:

resource "aws_autoscaling_group" "app" {
  # ... config ...
  
  instance_refresh {
    strategy = "Rolling"
    preferences {
      min_healthy_percentage = 90
    }
  }
}

4. Database migrations: Use RDS read replicas, promote to master, then update application connection strings via parameter store.

46. How do you implement disaster recovery for Terraform-managed infrastructure?

Answer: Multi-layered DR strategy I’ve implemented:

1. State file protection:

  • S3 versioning enabled
  • Cross-region replication for state bucket
  • Automated state backups to separate storage
  • MFA delete on production state buckets

2. Infrastructure as Code backup:

  • All code in version control (obviously)
  • Tagged releases for production
  • Mirror repositories in secondary Git provider

3. Multi-region deployment:

module "primary_region" {
  source = "./modules/infrastructure"
  providers = {
    aws = aws.us-east-1
  }
}

module "dr_region" {
  source = "./modules/infrastructure"
  providers = {
    aws = aws.us-west-2
  }
}

4. Recovery procedures: Documented runbooks for state restoration, tested quarterly in DR drills.

47. How do you handle Terraform provider version updates in production?

Answer: Provider updates can introduce breaking changes. My process:

1. Test in non-production first:

  1. Update provider version in dev environment
  2. Run terraform init -upgrade
  3. Run plan and check for unexpected changes
  4. Apply and validate
  5. Review provider changelog for breaking changes

2. Use version constraints properly:

# Allow patch updates, lock minor version
required_providers {
  aws = {
    source  = "hashicorp/aws"
    version = "~> 5.31.0"  # Allows 5.31.x, not 5.32.0
  }
}

3. Lock file: Commit terraform.lock.hcl to ensure consistent provider versions across team.

4. Emergency rollback: If provider update breaks prod, revert provider version in code and run apply.

48. Explain your approach to Terraform cost optimization and FinOps.

Answer: Infrastructure cost management through Terraform:

1. Cost estimation in CI/CD:

  • Integrate Infracost into pipelines
  • Show cost diff in PR comments
  • Block PRs that exceed budget thresholds

2. Right-sizing resources:

variable "environment_instance_types" {
  default = {
    dev     = "t3.micro"
    staging = "t3.small"
    prod    = "t3.large"
  }
}

resource "aws_instance" "app" {
  instance_type = var.environment_instance_types[var.environment]
}

3. Automated resource cleanup:

  • Destroy dev environments nightly
  • Use spot instances where appropriate
  • Auto-scaling based on actual usage

4. Tagging for cost allocation:

locals {
  common_tags = {
    Environment = var.environment
    Team        = var.team_name
    CostCenter  = var.cost_center
    ManagedBy   = "Terraform"
  }
}

resource "aws_instance" "app" {
  tags = merge(local.common_tags, {
    Name = "app-server"
  })
}

49. How do you implement compliance and policy enforcement with Terraform?

Answer: Multiple enforcement layers:

1. Pre-commit hooks:

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/antonbabenko/pre-commit-terraform
    hooks:
      - id: terraform_fmt
      - id: terraform_validate
      - id: terraform_tflint
      - id: terraform_checkov

2. Policy as Code with OPA:

# policy.rego
deny[msg] {
  resource := input.resource_changes[_]
  resource.type == "aws_s3_bucket"
  not resource.change.after.server_side_encryption_configuration
  msg := "S3 buckets must have encryption enabled"
}

3. Sentinel policies (Terraform Cloud/Enterprise):

# Require specific tags
import "tfplan/v2" as tfplan

required_tags = ["Environment", "Owner", "CostCenter"]

main = rule {
  all tfplan.resource_changes as _, rc {
    rc.type == "aws_instance" implies
    all required_tags as tag {
      rc.change.after.tags contains tag
    }
  }
}

4. AWS Service Control Policies: Enforce at organization level what Terraform can even create.

50. Design a Terraform architecture for a multi-cloud deployment (AWS + Azure + GCP).

Answer: This is the ultimate architecture question. Here’s how I structure it:

multi-cloud/
├── modules/
│   ├── compute/
│   │   ├── aws-ec2/
│   │   ├── azure-vm/
│   │   └── gcp-compute/
│   ├── networking/
│   │   ├── aws-vpc/
│   │   ├── azure-vnet/
│   │   └── gcp-vpc/
│   └── monitoring/
│       └── datadog/  # Cloud-agnostic monitoring
├── environments/
│   ├── dev/
│   ├── staging/
│   └── prod/
├── providers.tf
└── backend.tf

Key design principles:

1. Abstract cloud-specific differences:

module "app_server" {
  source = var.cloud_provider == "aws" ? "./modules/compute/aws-ec2" : 
           var.cloud_provider == "azure" ? "./modules/compute/azure-vm" :
           "./modules/compute/gcp-compute"
  
  instance_size = var.instance_size
  # Standardized interface regardless of cloud
}

2. Separate state files per cloud:

terraform {
  backend "s3" {
    bucket = "terraform-state"
    key    = "aws/prod/terraform.tfstate"
  }
}

# Or for Azure
terraform {
  backend "azurerm" {
    storage_account_name = "terraformstate"
    container_name      = "azure-prod"
  }
}

3. Use cloud-agnostic tools where possible:

  • Kubernetes for container orchestration
  • Consul for service discovery
  • Datadog/NewRelic for monitoring
  • Vault for secrets management

4. Multi-cloud considerations:

  • Network connectivity between clouds (VPN, Transit Gateway equivalents)
  • Unified IAM/RBAC strategy
  • Cross-cloud disaster recovery
  • Standardized tagging/labeling across clouds
  • Cost aggregation and comparison

Interview Preparation Tips

After conducting and taking many Terraform interviews, here’s what actually matters:

1. Have Real Examples Ready

For every technical answer, prepare a brief story from your experience. “I used this when…” is infinitely more compelling than reciting documentation.

2. Know Your Resume’s Terraform Claims

If you listed “Managed 500+ resources with Terraform,” be ready to explain the architecture, challenges you faced, and how you structured it. Interviewers will drill into anything on your resume.

3. Practice Whiteboarding

Many interviews ask you to design Terraform architecture on a whiteboard. Practice drawing module structures, state relationships, and provider configurations.

4. Understand Trade-offs

There’s rarely one “right” answer in Terraform. Be prepared to discuss why you’d choose one approach over another based on team size, infrastructure scale, or compliance requirements.

5. Stay Current

Terraform releases new features frequently. If interviewing in 2026, know about recent additions like terraform test, improved module testing, and any new meta-arguments or functions.

Frequently Asked Questions

How much Terraform experience do I need for different roles?

Junior roles (0-1 year) expect basic Terraform knowledge: writing resources, understanding state, using modules. Mid-level (1-3 years) requires production experience with state management, module design, and CI/CD integration. Senior roles (3+ years) demand architectural decisions, large-scale infrastructure management, and advanced patterns like multi-cloud or multi-account setups.

Should I get Terraform certified before interviewing?

The HashiCorp Terraform Associate certification is helpful but not required for most positions. It’s more valuable for career switchers or those with limited Terraform experience. Hands-on production experience trumps certification every time. That said, studying for the cert does give you structured learning.

What if I’m asked about Terraform features I’ve never used?

Be honest. Say “I haven’t used that feature in production, but based on my understanding…” and then explain your knowledge. Follow with a question about how they use it. This shows intellectual honesty and curiosity, both valued qualities.

How technical should I get in my answers?

Start with a high-level explanation, then offer to go deeper: “Would you like me to explain the technical details of how that works?” This lets the interviewer control the depth and shows you can communicate at different levels—crucial for working with both developers and management.

Are live coding/hands-on Terraform tests common?

Increasingly yes, especially for mid-level and senior roles. You might be asked to write Terraform code to provision specific resources, debug existing code, or design a module during the interview. Practice writing Terraform without IDE assistance—you might only have a basic text editor.

What about Terraform vs OpenTofu questions?

In 2026, you should be aware of OpenTofu (the open-source fork of Terraform). Some companies have migrated, others haven’t. Know the key differences: OpenTofu is BSL-free, Terraform has commercial features in Enterprise. The core concepts are the same, so if you know Terraform, you know OpenTofu.

How do I prepare if I only have experience with one cloud provider?

Focus on transferable concepts: state management, module design, backend configuration, CI/CD integration. These apply to any provider. If the job requires multi-cloud, be upfront about your AWS-only (or Azure-only) experience but emphasize your ability to learn new providers quickly—the patterns are similar.

What questions should I ask the interviewer?

Ask about their Terraform practices: How do they structure modules? What’s their state management strategy? How do they handle secrets? Do they use Terraform Cloud/Enterprise or self-host? What’s their biggest Terraform pain point? These questions show you’re thinking about the practical challenges they face.

Additional Resources

Level up your Terraform skills with these curated resources:

Official Documentation and Learning

Internal Resources

Conclusion

If you’ve made it through all 50 questions, you’re better prepared than 90% of Terraform interview candidates. But here’s what really matters: Terraform interviews aren’t about memorizing syntax or reciting documentation—they’re about demonstrating that you can manage infrastructure reliably at scale.

The best answers come from real experience. If you haven’t worked with production Terraform yet, get some practice. Spin up a personal project, contribute to open-source infrastructure, or volunteer to help with Terraform at your current job. There’s no substitute for actually dealing with state lock issues at 2 AM or refactoring a monolithic configuration into reusable modules.

Remember these key takeaways:

  • State management is the foundation—understand it deeply
  • Modules are how you scale Terraform beyond toy projects
  • Remote backends are non-negotiable for team collaboration
  • Security should be built in, not bolted on
  • Testing and CI/CD separate hobbyists from professionals

When you walk into that interview, you’re not just answering questions—you’re showing that you understand the trade-offs, the gotchas, and the real-world complexities of managing infrastructure as code. You’re demonstrating that when production breaks (and it will), you’re the person who can fix it.

One final piece of advice: don’t pretend to know something you don’t. A simple “I haven’t used that feature, but here’s how I’d approach it based on similar tools” is infinitely better than BS-ing your way through an answer. Interviewers can smell fake expertise a mile away, and honesty combined with problem-solving ability will get you much further.

Good luck with your interview. Now go build something with Terraform.


About the Author

Kedar Salunkhe

DevOps Engineer | Seven years of fixing things that break at 2am
Kubernetes • OpenShift • AWS • Coffe

I’ve spent almost 7 years keeping production systems running, often when everyone else is asleep. These days I’m working with Kubernetes and OpenShift deployments, automating everything that can be automated, and occasionally remembering to document the things I fix. When I’m not troubleshooting clusters, I’m probably trying out new DevOps tools or explaining to someone why we can’t just “restart everything” as a debugging strategy. You can usually find me where the coffee is strong and the error logs are confusing.

Leave a Comment