← Back to Interview Prep
TF

Terraform Interview Q&A

50 scenario-based Terraform interview questions with detailed answers — covering state management, modules, workspaces, CI/CD integration, and advanced patterns.

10 State Management10 Modules & Reusability5 Workspaces10 CI/CD & Workflow10 Advanced & Security5 Bonus
1

State Management & Locking

Q1.Your team is growing, and multiple developers are running Terraform simultaneously, causing conflicts. How do you resolve this?

  • Implement a remote backend (like AWS S3, Azure Blob Storage, or Terraform Cloud) to share the state file.
  • Enable State Locking using a DynamoDB table (for S3 backend) or Terraform Cloud's built-in locking.
  • This prevents concurrent executions from corrupting the state.

Q2.A teammate accidentally deleted the terraform.tfstate file from the remote S3 bucket. How do you recover?

  • Always enable object versioning on the S3 bucket used for the backend.
  • You can recover the deleted state file by restoring the previous version of the object in the S3 console or using the AWS CLI.

Q3.Your cloud team manually created an EC2 instance. You now need to manage it via Terraform without destroying it. How?

  • Write the resource configuration block in your .tf file matching the existing resource.
  • Run: terraform import aws_instance.my_ec2 i-1234567890
  • This maps the existing infrastructure to your Terraform state without destroying it.

Q4.You want to stop managing a database with Terraform but keep the database running in AWS. What command do you use?

  • Use the terraform state rm command.
  • This removes the resource from the Terraform state file without destroying the actual physical resource in the cloud provider.

Q5.You have a massive state file that takes 10 minutes to plan. You want to split it into two smaller projects. How do you migrate the state?

  • Create a new Terraform directory/project.
  • Use: terraform state mv -state-out=../new-project/terraform.tfstate aws_instance.app aws_instance.app
  • This moves specific resources from the old state file to the new one.

Q6.Your state file contains sensitive database passwords in plain text. How do you secure it?

  • Store the state file in a secure remote backend (like S3) and enable encryption at rest using AWS KMS.
  • Apply strict IAM policies (RBAC) so only authorized pipelines/users can read the state bucket.
  • Enable server-side encryption and consider using Terraform Cloud/Enterprise which encrypts state by default.

Q7.Someone manually changed the tags on an S3 bucket in the AWS console. How do you force Terraform to update its state to reflect reality?

  • Run: terraform apply -refresh-only
  • This updates the state file with the real-world infrastructure without making any modifications to resources.

Q8.Terraform fails to release a state lock because your CI/CD pipeline crashed mid-run. How do you fix this?

  • Use: terraform force-unlock <LOCK_ID>
  • You can find the Lock ID in the error message output.
  • Use this cautiously — ensure no one else is actually running a plan/apply before force unlocking.

Q9.You renamed a resource block from aws_instance.web to aws_instance.frontend. Terraform wants to destroy and recreate it. How do you prevent this?

  • Option 1 (Terraform 1.1+): Use the moved block in your config:
  • moved { from = aws_instance.web to = aws_instance.frontend }
  • Option 2: Use terraform state mv aws_instance.web aws_instance.frontend to rename it in the state file manually.

Q10.You want to test a destructive Terraform change locally without affecting the actual remote state file used by the team.

  • Pull a local copy of the state: terraform state pull > local.tfstate
  • Test against this local file by adjusting the backend configuration to local.
  • Alternatively, use Terraform Workspaces to create a completely isolated environment.
2

Modules & Reusability

Q11.You have 5 different microservices that all need identical VPC and Subnet configurations. How do you avoid code duplication?

  • Create a custom Terraform Module for the networking infrastructure.
  • Call this module from the root configuration of each microservice, passing in necessary variables.
  • This enforces consistency and centralises changes to a single place.

Q12.Your root module needs the IP address of an EC2 instance that was created inside a child module. How do you retrieve it?

  • Define an output block in the child module that exports the value:
  • output "instance_ip" { value = aws_instance.app.public_ip }
  • In the root module, reference it using module.module_name.instance_ip.

Q13.A new update to a public community module breaks your infrastructure. How do you prevent this in the future?

  • Always pin module versions using the version argument:
  • version = "~> 2.0.0"
  • This ensures Terraform only pulls compatible patch/minor versions and ignores breaking major updates.

Q14.You want to conditionally deploy a monitoring module only in the "production" environment.

  • Use the count meta-argument in the module block:
  • count = var.environment == "production" ? 1 : 0
  • When count is 0, Terraform skips the module entirely.

Q15.You are creating a database module and an app server module. The app server must wait for the database to finish provisioning. How?

  • Use the depends_on meta-argument within the app server module block:
  • depends_on = [module.database]
  • This forces Terraform to provision the database module before starting the app server module.

Q16.You are referencing a module stored in a private GitHub repository. How does Terraform authenticate to fetch it?

  • For HTTPS: configure a .netrc file or set environment variable GITHUB_TOKEN.
  • For SSH: ensure your SSH key is configured on the machine running Terraform.
  • Terraform Cloud/Enterprise can store VCS credentials for module registry access.

Q17.You need to create 10 identical S3 buckets with slightly different names. How do you do this efficiently in a module?

  • Use the for_each meta-argument with a set of bucket name strings:
  • for_each = toset(["logs", "backups", "assets", ...])
  • Reference each.key inside the resource block to create unique names dynamically.

Q18.Your module creates a KMS key. The root module needs that key ARN to encrypt an S3 bucket. How do you wire this together?

  • Create an output in the KMS module: output "key_arn" { value = aws_kms_key.this.arn }
  • In the root module, reference it when configuring the S3 module:
  • kms_key_arn = module.kms.key_arn

Q19.You want to publish a reusable internal Terraform module so all teams in your company can use it. What is the best approach?

  • Publish it to a Private Terraform Registry (in Terraform Cloud/Enterprise) or a private Git repository.
  • Version the module using Git tags (e.g., v1.0.0, v1.1.0).
  • Teams reference it with a source URL and pinned version tag.

Q20.A module you depend on has a breaking change in its input variable names. How do you upgrade without downtime?

  • Create a compatibility wrapper: keep old variable names in your root config and map them to the new module variables.
  • Update the module version and variables in a staging workspace first.
  • After validation, upgrade production with terraform plan and apply with a maintenance window.
3

Workspaces & Environments

Q21.You want to manage dev, staging, and production with the same Terraform code but different variable values. What approaches can you use?

  • Option 1: Terraform Workspaces — one workspace per environment (terraform workspace new staging).
  • Option 2: Directory-per-environment — separate folders with their own .tfvars files.
  • Option 3: Terragrunt — DRY wrapper tool that calls the same module with environment-specific inputs.

Q22.You created a resource in the "dev" workspace by mistake. It should only be in "staging". How do you move it?

  • You cannot move state between workspaces directly.
  • You must terraform destroy the resource in dev, switch to the staging workspace, and re-apply.
  • Alternatively, manually edit state files (risky and not recommended in production).

Q23.How do you reference the current workspace name inside a Terraform configuration?

  • Use the built-in variable: terraform.workspace
  • Example: name = "bucket-${terraform.workspace}"
  • This lets you create environment-specific resource names dynamically.

Q24.Your team wants to spin up a complete temporary environment for each feature branch and destroy it after merge. How do you design this?

  • Create a Terraform workspace per feature branch in your CI/CD pipeline.
  • On PR open: terraform workspace new feature-xyz && terraform apply.
  • On PR merge: terraform destroy && terraform workspace delete feature-xyz.

Q25.Your production workspace accidentally used the wrong .tfvars file and deployed with dev settings. How do you prevent this?

  • Enforce strict CI/CD pipeline controls that automatically select the correct .tfvars file based on the branch or workspace.
  • Use naming conventions in the pipeline: -var-file=${workspace}.tfvars.
  • Add plan review gates (manual approval step) before production applies.
4

CI/CD & Workflow

Q26.You want to integrate Terraform into a CI/CD pipeline (e.g., GitHub Actions). What is the ideal workflow?

  • 1. On Pull Request: run terraform fmt -check, terraform validate, terraform plan.
  • 2. Post plan, post a comment on the PR with the plan output for team review.
  • 3. On merge to main: run terraform apply -auto-approve.
  • 4. Use OIDC (no static keys) for cloud authentication.

Q27.A terraform plan in CI shows 200 resources being deleted due to a bug. How do you stop an accidental apply?

  • Always add a manual approval/gate step before apply in CI/CD (e.g., environment protection rules in GitHub Actions).
  • Use terraform plan -out=plan.tfplan and only apply after explicit human review.
  • Set OPA (Open Policy Agent) or Sentinel policies to block plans that destroy more than N resources.

Q28.You need to provision resources in 3 different AWS accounts simultaneously. How do you structure this in Terraform?

  • Use multiple provider blocks with aliases, each configured with different AWS account credentials.
  • provider "aws" { alias = "dev_account" ... }
  • Reference each provider in resources: provider = aws.dev_account.

Q29.How do you securely pass sensitive values like database passwords to Terraform in a CI/CD pipeline?

  • Store secrets in a secrets manager (AWS Secrets Manager, HashiCorp Vault, GitHub Actions secrets).
  • Inject them as environment variables (TF_VAR_db_password) at pipeline runtime.
  • Never commit .tfvars files with secrets to version control — add them to .gitignore.

Q30.Your Terraform apply failed halfway through, leaving infrastructure in a partially created state. How do you recover?

  • Terraform is idempotent — simply re-run terraform apply.
  • Terraform will detect which resources were already created (via state) and only create the remaining ones.
  • If a resource is in a bad state, you may need to terraform taint it to force recreation.

Q31.Your CI/CD pipeline takes 40 minutes to plan because it refreshes state against 500 resources. How do you speed it up?

  • Use terraform plan -refresh=false to skip the live state refresh (use only when you are confident no out-of-band changes occurred).
  • Break the monolith into smaller modules with separate state files.
  • Use terraform plan -target=resource to plan only the changed component.

Q32.How do you ensure that only a specific version of Terraform is used by all team members and CI/CD?

  • Set the required_version constraint in your terraform block: required_version = "~> 1.8.0".
  • Use tfenv (CLI tool) locally to automatically switch to the required version.
  • Pin the Terraform version in the CI/CD runner image or action configuration.

Q33.Two team members opened PRs at the same time, both modifying the same resource. Both plans look clean. What happens when they both apply?

  • The first apply acquires the state lock and completes.
  • The second apply will fail with a "state locked" error and wait or timeout.
  • After the first apply completes, the second apply's plan is now stale — it must re-run terraform plan before applying.

Q34.You need to rotate a secret (e.g., RDS password) managed by Terraform without any downtime. How do you approach this?

  • Update the secret value in your secrets manager (Vault/Secrets Manager) and reference it as a data source.
  • Terraform will detect the change on next apply and update the resource.
  • For RDS, use the skip_final_snapshot = true and lifecycle { ignore_changes } carefully to avoid unintended recreation.

Q35.Your Terraform code works perfectly locally but fails in CI with a "provider not found" error. What do you investigate?

  • Ensure the CI environment runs terraform init before plan/apply.
  • Check if the .terraform.lock.hcl file is committed and the providers match the CI OS/architecture.
  • Verify network access from the CI runner to the Terraform provider registry (registry.terraform.io).
5

Advanced Patterns & Security

Q36.You need to create an IAM role that grants access to all S3 buckets created by the same Terraform config. How do you do this dynamically?

  • Use the aws_s3_bucket resource with for_each, collect all bucket ARNs using values() and *.arn, and pass them to the IAM policy resource.
  • resource "aws_iam_policy" "s3" { ... Resource = [ for b in aws_s3_bucket.all : b.arn ] }

Q37.Your Terraform apply creates a new EC2 instance and immediately terminates the old one, causing downtime. How do you achieve zero-downtime replacement?

  • Use the lifecycle block with create_before_destroy = true.
  • Terraform will provision the new instance first, then destroy the old one.
  • Combine with a load balancer health check to ensure the new instance is healthy before traffic shifts.

Q38.You need to manage resources across 5 AWS regions from one Terraform project. How do you handle this?

  • Define multiple provider blocks with different region and alias values.
  • provider "aws" { alias = "eu_west_1" region = "eu-west-1" }
  • Reference the alias in each resource: provider = aws.eu_west_1.

Q39.A third-party API you provision via Terraform occasionally times out, causing apply failures. How do you handle this gracefully?

  • Use the timeouts block inside the resource configuration to extend default create/update/delete timeouts.
  • timeouts { create = "30m" update = "20m" }
  • Combine with retry logic in a wrapper script or rely on the provider's built-in retry mechanisms.

Q40.How do you enforce organisational security policies (e.g., no S3 buckets with public access) across all Terraform applies?

  • Use Sentinel (Terraform Enterprise/Cloud) or Open Policy Agent (OPA) for policy-as-code.
  • Define policies that parse the Terraform plan JSON and fail if forbidden configurations are detected.
  • Integrate these checks into the CI/CD pipeline as a required gate before apply.

Q41.You want to use a specific AMI ID that changes every month with new patches. How do you keep your Terraform code up to date automatically?

  • Use the aws_ami data source with filters for Owner and Name pattern.
  • data "aws_ami" "latest" { most_recent = true owners = ["amazon"] filter { name = "name" values = ["amzn2-ami-hvm-*-x86_64-gp2"] } }
  • Reference data.aws_ami.latest.id instead of hardcoding the AMI ID.

Q42.You want to run a database migration script every time a new RDS instance is created. How do you do this in Terraform?

  • Use a null_resource with a local-exec provisioner tied to the RDS resource.
  • Use triggers = { rds_endpoint = aws_db_instance.main.endpoint } so it re-runs only when the DB changes.
  • Note: Provisioners are a last resort in Terraform — prefer external tools like Flyway or Liquibase managed outside Terraform.

Q43.Your company has 30 Terraform root modules. How do you ensure they all use the same, company-approved provider versions?

  • Create a shared required_providers configuration that teams copy as a standard template.
  • Use a private Terraform module registry to distribute a "bootstrap" module that enforces provider versions.
  • Enforce .terraform.lock.hcl commits in git so versions are locked per repo.

Q44.How would you architect Terraform to manage a SaaS platform that needs to spin up isolated infrastructure per customer?

  • Create one Terraform module representing a complete customer infrastructure stack.
  • Use a for_each on a map of customer configurations to instantiate the module per customer.
  • Store each customer's state in an isolated state file (e.g., S3 key: customers/<customer_id>/terraform.tfstate).

Q45.You need to pass the output of a Python script to a Terraform resource. How do you do this?

  • Use the external data source provider.
  • Define a data "external" block that runs your Python script and reads its JSON output.
  • Reference the output as data.external.my_script.result["key_name"] in your resource.

🎯 Pro Tip for Terraform Interviews

Always anchor your answers with a real scenario from your experience. Interviewers love hearing about actual state corruption issues you fixed or modules you built.

← Back to All Interview Guides