Interview Q&A · 40 questions · 18 answered publicly
Terraform Interview Questions
Ordered by how often they're asked. Sign in free to see every answer, rate your confidence and run timed mock interviews.
-
Most asked What is Terraform, and how does it work at a high level?
Summary
Terraform is an infrastructure-as-code tool: you declare resources in HCL configuration files, and Terraform builds a dependency graph, compares the configuration with the recorded state and the real infrastructure, produces a plan of creates, updates and deletes, and applies it through providers that call cloud and service APIs.
Longer Answer
Key pieces: providers (plugins for AWS, Azure, GCP, Kubernetes, GitHub, Datadog, and thousands more), resources (things Terraform manages), data sources (read-only lookups), variables, locals and outputs, modules (reusable groups of resources), and state (Terraform's record of what it manages and the real IDs).
Terraform is declarative: you describe the end state, not the steps. Because it calls APIs, the same workflow manages many platforms. Since HashiCorp moved Terraform to the Business Source License in 2023, the community fork OpenTofu (Linux Foundation, MPL licence) offers a compatible open-source alternative.
Key Points
- Declarative HCL configuration.
- Plan = diff of config, state and reality.
- Providers call APIs.
- OpenTofu is the open-source fork.
-
Most asked What is Terraform state, why is it needed, and where should it be stored?
Summary
State maps resources in your configuration to real objects (IDs, attributes), records dependencies and metadata, and lets Terraform compute plans quickly. For teams it must be stored remotely in a shared backend with locking (for example S3, Azure Blob Storage, Google Cloud Storage, or HCP Terraform), never committed to Git.
Longer Answer
Why remote: everyone and every pipeline must see the same state; locking stops two applies from running at once and corrupting it; and the backend can be versioned and encrypted. State often contains secrets (database passwords, generated keys) in plain text, so restrict access, encrypt at rest and enable versioning so you can recover from mistakes.
With the S3 backend, recent Terraform versions support native lock files in S3 (
use_lockfile = true), replacing the older DynamoDB lock table.Code Example
terraform { backend "s3" { bucket = "acme-terraform-state" key = "prod/network/terraform.tfstate" region = "eu-west-1" encrypt = true use_lockfile = true } }Key Points
- Maps config to real resource IDs.
- Remote backend with locking and versioning.
- State can contain secrets: protect it.
- Never commit state to Git.
-
Most asked Walk through terraform init, plan and apply. What does each do?
Summary
initconfigures the backend and downloads providers and modules (recording provider versions in.terraform.lock.hcl);planrefreshes the state from real infrastructure, compares it with the configuration and shows the proposed changes;applyexecutes a plan (ideally a saved plan file reviewed earlier) and updates the state.Longer Answer
In CI/CD, run
terraform plan -out=tfplanon pull requests, post the plan for review, and apply exactly that saved plan after approval, so what was reviewed is what runs.terraform fmt -checkandterraform validatecatch formatting and syntax errors early.destroyremoves everything in the configuration and should be heavily restricted in production.Read plans carefully for
-/+(destroy and recreate) and-(destroy) actions: a renamed resource or a changed immutable attribute can replace a database.Key Points
- init: backend, providers, modules, lock file.
- plan: refresh + diff.
- apply: execute (a saved plan).
- Watch for replacements in plans.
-
Most asked What are Terraform modules, and how do you design good ones?
Summary
A module is a directory of Terraform configuration with input variables and outputs that can be called repeatedly; every configuration is a root module that may call child modules from local paths, Git, or a registry. Good modules encapsulate one meaningful concept (a VPC, a service, a database), expose a small, well-documented interface, and have sensible defaults.
Longer Answer
Guidelines: avoid thin wrappers around a single resource; avoid "god modules" that do everything with dozens of flags; pin module versions (registry versions or Git tags); validate inputs (
validationblocks, types); output the values consumers need; and do not configure providers inside reusable modules (pass them in). Document with examples, and test withterraform testor Terratest.Organisations often publish internal modules in a private registry so teams self-serve approved patterns (encrypted buckets, tagged resources).
Key Points
- Reusable units with inputs and outputs.
- One meaningful concept per module.
- Pin versions; validate inputs.
- No provider configuration inside modules.
-
Most asked count or for_each: when do you use each?
Summary
Use
for_each(over a map or set of strings) when creating several similar resources identified by meaningful keys; usecountmainly for conditionally creating zero or one resource (count = var.enabled ? 1 : 0).for_eachkeys resources by name, so adding or removing one item does not affect the others.Longer Answer
With
count, resources are addressed by index (aws_s3_bucket.this[0]). Removing an item from the middle of a list shifts every later index, so Terraform plans to destroy and recreate resources that did not really change. Withfor_each, addresses are stable keys (aws_s3_bucket.this["logs"]). Keys must be known at plan time, so you cannot use values computed during apply (such as generated IDs) as keys.Code Example
resource "aws_s3_bucket" "this" { for_each = toset(["logs", "assets", "backups"]) bucket = "acme-${each.key}-prod" }Key Points
- for_each: stable keys for collections.
- count: on/off toggles.
- Removing from a count list shifts indexes.
- for_each keys must be known at plan time.
-
Most asked How do you handle secrets in Terraform?
Summary
Keep secrets out of code and version control: read them at runtime from a secret manager (AWS Secrets Manager, Vault) through data sources or let services generate and store them (for example RDS-managed master passwords), mark variables and outputs
sensitive, and protect the state, because values Terraform reads or creates are stored there in plain text.Longer Answer
Newer Terraform versions reduce exposure with ephemeral resources and values (not persisted to plan or state) and write-only arguments for passwords, where the provider supports them. Provide credentials to Terraform itself through short-lived identities (OIDC from CI to the cloud), not long-lived keys in variables. Restrict who can read state, enable encryption, and avoid outputting secrets.
Key Points
- No secrets in code or Git.
- Fetch from secret managers or let services manage them.
- State stores values in plain text: protect it.
- Ephemeral/write-only where available; OIDC for CI.
-
Most asked How would you run Terraform in CI/CD?
Summary
On every pull request:
fmt -check,validate, linting and security scanning, thenplan -outwith the plan posted to the PR. After review and approval: apply that saved plan from a pipeline with locked, audited credentials, one environment at a time. Tools such as Atlantis, HCP Terraform, Spacelift, env0 or GitHub Actions workflows implement this.Longer Answer
Important details: authenticate CI to the cloud with OIDC federation and short-lived roles (separate plan-only and apply roles); ensure only one apply per state at a time (locking, pipeline concurrency); require approvals for production; keep plan artifacts for audit; and run scheduled drift-detection plans. Never let engineers apply production from laptops as normal practice.
Key Points
- PR: fmt, validate, scan, plan.
- Apply the reviewed plan after approval.
- OIDC credentials; plan vs apply roles.
- No routine laptop applies to prod.
-
Most asked A terraform plan wants to destroy and recreate a database. What do you do?
Summary
Stop and find out why before applying. Look at which attribute is marked
# forces replacement: a changed immutable attribute (engine version major, subnet group, identifier), a renamed resource or module (use amovedblock), a changedcountindex, or a provider upgrade changing defaults. Then fix the configuration so the plan shows an in-place update, or plan a deliberate migration.Longer Answer
Safeguards to have in place before this happens:
prevent_destroyon critical data stores, deletion protection on the resource itself (RDSdeletion_protection), final snapshots, CI checks that flag destroy actions on protected resource types, and required human approval when plans contain replacements. If a replacement really is needed (for example to change encryption), migrate data explicitly with snapshots or replication rather than letting Terraform delete and recreate.Key Points
- Find the 'forces replacement' attribute.
- Renames: moved blocks; index shifts: for_each.
- prevent_destroy + deletion protection.
- Flag destroys in CI; migrate data deliberately.
-
Most asked What lifecycle settings does Terraform offer, and when do you use them?
Summary
create_before_destroycreates the replacement before deleting the old resource (avoiding downtime for things like certificates or launch templates);prevent_destroymakes any plan that would destroy the resource fail (protecting databases and state buckets);ignore_changesstops Terraform from reverting attributes managed elsewhere (for example a desired count changed by an autoscaler);replace_triggered_byforces replacement when another value changes.Longer Answer
Use them deliberately:
ignore_changescan hide real drift, andprevent_destroyonly protects against Terraform plans (removing the resource block from configuration removes the protection too). Preconditions and postconditions inlifecycleblocks validate assumptions, such as an AMI being the right architecture, with clear error messages.Key Points
- create_before_destroy avoids gaps.
- prevent_destroy protects critical resources.
- ignore_changes for externally managed attributes.
- Pre/postconditions validate assumptions.
-
Most asked What is drift, and how do you detect and handle it?
Summary
Drift is a difference between the real infrastructure and what Terraform's configuration and state say, usually from manual console changes, other tools or scripts, or provider-side defaults changing.
terraform plan(which refreshes state) shows it; scheduled plan runs in CI or HCP Terraform drift detection catch it continuously.Longer Answer
When you find drift, decide whether the real-world change should be kept (update the configuration to match, possibly with
ignore_changesfor values another system owns) or reverted (apply the configuration). The real fix is process: restrict console write access in production, route changes through code review, and alert on drift.terraform plan -refresh-onlyupdates state to match reality without changing infrastructure.Key Points
- Reality differs from config/state.
- Detect with scheduled plans.
- Adopt or revert, deliberately.
- Prevent with access controls and process.
-
Most asked How do you bring existing infrastructure under Terraform management?
Summary
Use
importblocks (Terraform 1.5+) in configuration, which are planned and reviewed like any change, optionally withterraform plan -generate-config-out=generated.tfto generate a starting configuration for the imported resources. The olderterraform importCLI command imports one resource at a time into state without configuration.Longer Answer
Workflow: write import blocks with the target address and real ID, generate or hand-write the resource configuration, run plan until it shows no changes (meaning configuration matches reality), then apply to record it in state, and clean up the generated code into modules. Tools such as Terraformer or provider-specific exporters help with large estates. Import is also how you recover when a resource exists but state lost track of it.
Key Points
- import blocks (1.5+) are reviewable.
- Generate config with -generate-config-out.
- Iterate until plan shows no changes.
- Clean up into modules.
-
Most asked How do you refactor Terraform code without destroying resources? Explain moved blocks and state mv.
Summary
When you rename a resource or move it into a module, Terraform would otherwise plan to destroy the old address and create a new one. A
movedblock (Terraform 1.1+) records the old and new addresses in configuration, so the plan shows a move instead of a replacement;terraform state mvdoes the same imperatively.Longer Answer
moved { from = aws_instance.web to = module.web.aws_instance.this }movedblocks are better for shared code because every workspace and pipeline applies them consistently and they can be reviewed.removedblocks (Terraform 1.7+) stop managing a resource without destroying it (replacingterraform state rm). Always check the plan shows moves, not destroys, before applying.Key Points
- Renames look like destroy + create.
- moved blocks record address changes.
- removed blocks forget without destroying.
- Verify the plan shows moves.
-
Most asked Workspaces, separate state files, or separate directories: how do you manage multiple environments?
Summary
Terraform CLI workspaces give one configuration several state files (dev, staging, prod) selected at runtime, which is convenient but makes environments look identical and easy to confuse. Many teams prefer separate root modules or directories per environment (each with its own backend key and variables) that call shared modules, or tools such as Terragrunt.
Longer Answer
Separate directories make differences explicit (prod has more replicas, different instance sizes), allow different provider credentials and approval rules per environment, and reduce the risk of applying to prod by mistake. Workspaces suit short-lived copies of the same stack (feature environments). HCP Terraform "workspaces" are a different concept: each is effectively a separate state with its own variables and permissions.
Key Points
- CLI workspaces: one config, many states.
- Separate root modules per environment are explicit.
- Different credentials and approvals per environment.
- HCP workspaces differ from CLI workspaces.
-
Most asked How do you pin provider and module versions, and what is the dependency lock file?
Summary
Declare
required_providerswith version constraints (for example~> 5.0) andrequired_versionfor Terraform itself; pin module versions; and commit.terraform.lock.hcl, which records the exact provider versions and checksums chosen byinit, so every machine and pipeline uses the same provider builds.Longer Answer
Upgrade deliberately with
terraform init -upgradein a branch, read provider changelogs (major versions often change resource behaviour), and review the plan. Unpinned providers cause surprise changes when a new major version is released. Generate lock-file hashes for every platform your team uses (terraform providers lock -platform=...) to avoid mismatches between macOS laptops and Linux CI.Key Points
- required_providers + required_version.
- Commit .terraform.lock.hcl.
- Upgrade deliberately; read changelogs.
- Lock hashes for all platforms.
-
Most asked Terraform and Ansible: how do they differ, and do you need both?
Summary
Terraform is declarative provisioning of infrastructure through APIs, tracking state to manage the full lifecycle (create, update, destroy). Ansible is primarily configuration management and orchestration: it connects to machines (SSH, WinRM) or APIs and runs tasks, usually without a state file, best for configuring operating systems and software on existing hosts.
Longer Answer
Common split: Terraform creates networks, instances and managed services; Ansible (or images built with Packer) configures the software on hosts. With immutable infrastructure and containers, much of the configuration-management need moves into image builds, so many teams need Ansible less. Both can technically overlap, but using each for its strength avoids fighting the tool.
Key Points
- Terraform: declarative provisioning with state.
- Ansible: configuration and orchestration.
- Often used together.
- Immutable images reduce config management needs.
-
Most asked What are the most common Terraform mistakes you have seen in teams?
Summary
Local state or state in Git; no locking; one giant state for everything; using
countfor collections; unpinned providers; secrets in variables files committed to Git; manual console changes causing drift; applying from laptops; huge copy-pasted configurations instead of modules (or over-engineered modules); and not reading plans before applying.Longer Answer
Each has a clear fix: remote, locked, versioned state; smaller stacks;
for_each; pinned versions and lock files; secret managers and sensitive values; restricted console access with drift detection; CI-based applies with reviewed plans; sensible module boundaries; and a culture of reviewing every plan, especially for destroys and replacements.Key Points
- State handling mistakes.
- count, unpinned versions, secrets in Git.
- Drift and laptop applies.
- Not reading plans.
-
Most asked Compare Terraform with CloudFormation, CDK and Pulumi.
Summary
Terraform is multi-cloud and multi-service with a huge provider ecosystem and HCL configuration; CloudFormation is AWS's native IaC service (state managed by AWS, deep AWS integration, AWS-only); AWS CDK and CDK for Terraform let you write infrastructure in programming languages that synthesise to CloudFormation or Terraform; Pulumi uses general-purpose languages directly with its own engine and state.
Longer Answer
Choose Terraform/OpenTofu for multi-cloud or SaaS providers (Datadog, GitHub, Cloudflare) and a large hiring pool; CloudFormation/CDK for AWS-only shops that want AWS-managed state and same-day support for new services; Pulumi or CDK when teams strongly prefer real programming languages for abstraction and testing. Consistency across the organisation often matters more than which tool is slightly better.
Key Points
- Terraform: multi-cloud ecosystem.
- CloudFormation: AWS-native, managed state.
- CDK/Pulumi: programming languages.
- Consistency matters most.
-
Most asked Terraform or OpenTofu: what is the difference, and how would you choose?
Summary
In August 2023 HashiCorp relicensed Terraform from MPL 2.0 to the Business Source License, which restricts offering competing services. OpenTofu forked the last MPL version and is developed under the Linux Foundation; it is largely compatible with Terraform configuration and providers and has added its own features, such as client-side state encryption.
Longer Answer
For most companies using Terraform internally, the BSL does not restrict use; the choice is about licence preference, vendor relationship (HCP Terraform features), and feature roadmap divergence over time. Tooling such as Atlantis, Terragrunt and many CI platforms supports both. Migration is usually straightforward but should be tested, and the two are drifting apart with new features, so avoid mixing them on the same state.
Key Points
- BSL relicence in 2023; OpenTofu fork under LF.
- Largely compatible; diverging features.
- Choice: licence, vendor, features.
- Do not mix on one state.
- How should you split Terraform state for a large organisation?
- What is policy as code for Terraform, and which tools are used?
- How do you test Terraform code?
- How does Terraform determine the order in which it creates resources?
- What is the difference between variables, locals and outputs?
- What are data sources, and when should you use them?
- What do dynamic blocks, for expressions and conditionals give you, and when do they hurt?
- How do you manage multiple accounts, regions or subscriptions in one Terraform configuration?
- The Terraform state lock is stuck. How do you handle it?
- What are provisioners, and why are they considered a last resort?
- How do you structure a Terraform repository for a team?
- How do you manage Kubernetes resources with Terraform, and what are the pitfalls?
- How do you handle large-scale changes, such as a provider major version upgrade across many stacks?
- What does 'known after apply' mean, and why can it cause problems?
- How do you design a reusable Terraform module for an internal platform team to offer, for example 'a secure S3 bucket'?
- How do you roll back a bad Terraform change?
- What is the difference between terraform refresh, plan -refresh-only and apply -refresh-only?
- What are check blocks and pre/postconditions used for?
- What is Terragrunt, and when is it useful?
- How do you tag resources consistently with Terraform?
- What is HCP Terraform (Terraform Cloud), and what does it add?
- What is Terraform's resource graph parallelism, and when would you change it?