Terraform Interview Questions

Common Terraform interview questions on state, plan vs apply, modules, and remote backends.

A curated set of Terraform interview questions, from core concepts to team workflow practices.

Q: What is the purpose of Terraform's state file, and why does it matter? The state file records which real-world infrastructure objects correspond to which resources in your configuration — it's what lets Terraform know what already exists versus what your config additionally describes. Without it, every apply would have no way to distinguish "create this" from "this already exists, leave it alone," and would have to either recreate everything from scratch or fail. It's also the mechanism behind terraform plan: comparing config against state against real infrastructure is how Terraform computes exactly what would change.

Q: What's the difference between terraform plan and terraform apply? terraform plan computes and displays what Terraform would change — resources to create, update, or destroy — by comparing your configuration against the current state, without touching any real infrastructure. terraform apply re-runs that same comparison and then, after confirmation, actually makes the API calls to bring reality in line with it. Separating the two is what makes infrastructure changes reviewable: the plan output can be read, and ideally posted for review, before anyone commits to actually applying it.

Q: Why use modules instead of writing every resource block directly in the root configuration? Modules package a reusable, parameterized unit of infrastructure — the same idea as a function — so a pattern like "a web server with a security group and an attached EBS volume" can be defined once and called multiple times with different inputs (per environment, per service) instead of being copy-pasted and slowly drifting out of sync across each copy. They also let a team standardize on vetted, well-tested infrastructure patterns (whether written in-house or pulled from the public Terraform Registry) rather than every engineer reinventing the same VPC or database setup slightly differently.

Q: Why does remote state matter for a team, rather than just using a local state file? A local state file lives on one person's machine, isn't shared automatically with teammates or CI, and has no locking — if two people (or a person and a CI pipeline) run apply against it concurrently, the state can be corrupted or changes silently overwritten. A remote backend (an S3 bucket with DynamoDB locking, or Terraform Cloud) gives the whole team and any automation a single, shared, lock-protected source of truth for what infrastructure has actually been applied, which is a requirement rather than a nice-to-have once more than one person or process touches the same infrastructure.

Q: What happens if someone makes a manual change in the cloud console to a resource Terraform manages? This is called configuration drift — the real infrastructure no longer matches what the state file (and configuration) describe. The next terraform plan will detect the difference and propose a change to bring the resource back in line with the configuration, which may mean reverting the manual change entirely, sometimes unexpectedly if nobody realized the manual edit had been made. This is one of the main practical arguments for disciplined IaC usage: once a resource is managed by Terraform, changes to it should go through configuration and apply, not ad hoc console edits.

Q: What does state locking actually protect against, and what happens if two people try to apply at the same time? Locking prevents two plan/apply operations from reading and writing the same state file concurrently. With a backend that supports it (S3 + DynamoDB, or S3's native locking since Terraform 1.10), the first operation acquires a lock before making any changes; a second operation started while the first is still running fails immediately with an "Error acquiring the state lock" message identifying who holds it, rather than silently racing and potentially corrupting the state. The fix is almost always to wait and retry — terraform force-unlock should only be used once you've confirmed the lock is genuinely stale, such as after a CI job crashed mid-apply.

Q: How would you set up remote state for a brand-new AWS project, given that the S3 bucket and DynamoDB table are themselves infrastructure? This is the classic bootstrapping problem: you can't have a configuration create the exact backend resources it then uses as its own backend, because terraform init needs the backend to exist first. The standard solution is a small, separate "bootstrap" configuration — applied once with plain local state — whose only job is creating the S3 bucket (with versioning and encryption enabled) and the DynamoDB table (with a partition key named exactly LockID). Every other configuration then simply references those already-existing resources in its own backend block.

Q: How do you let one Terraform configuration use an output value from a completely separate configuration? The terraform_remote_state data source reads another configuration's state file directly (given its backend type and connection details) and exposes that configuration's declared outputs under data.terraform_remote_state.<name>.outputs.<output_name>. It only works for values the source configuration explicitly exposed via an output block — it's the mechanism that makes splitting infrastructure into independently-applied configurations (a network config, an app config, a database config) practical, since each layer can still consume values produced by the layers below it.

Q: What's the difference between using Terraform workspaces and using separate root-configuration directories for staging vs. production? Workspaces share one set of .tf files across environments, switching only which state file is active — minimal duplication, but any real structural difference between environments (production needing a Multi-AZ database staging doesn't) has to be expressed as conditionals inside otherwise-shared resource blocks. Separate directories give each environment its own independent root configuration (typically calling the same shared modules with different arguments), so environments can genuinely diverge structurally, at the cost of some duplication at the root level. Most teams whose environments accumulate real differences over time end up preferring separate directories for exactly this reason.

Q: Besides terraform validate, what tools would you add to a CI pipeline to catch problems Terraform itself won't? terraform validate only confirms a configuration is internally consistent — valid HCL, correct argument types — without knowing anything about whether a chosen value makes sense for a real cloud provider or is a security risk. tflint adds provider-aware linting (catching an invalid instance type, or a variable declared but never used), while checkov scans for known-risky patterns like publicly exposed storage buckets or overly permissive security groups, entirely without needing to apply anything. Both run cheaply, without cloud credentials, on every push, well before a plan (which does need credentials) ever runs.