IaC & Terraform Interview Questions
Terraform interviews tend to probe whether you actually understand the model behind the tool: how desired state becomes real infrastructure, why state exists, and what a typical change looks like end to end. The questions below are grouped by theme so you can drill one area at a time, with short HCL where a concrete example clarifies the answer. Aim to explain the why, not just recite a command.
IaC concepts
What is Infrastructure as Code?
Infrastructure as Code is the practice of defining and provisioning infrastructure (networks, compute, databases, IAM) through machine-readable configuration files instead of manual console clicks. The configuration is versioned, reviewed, and applied automatically, so infrastructure becomes repeatable and auditable.
What is the difference between declarative and imperative IaC?
Imperative tooling specifies the steps to reach a result; declarative tooling specifies the desired end state and lets the engine compute the steps. Terraform is declarative: you describe what should exist and it figures out the create/update/delete actions.
What is idempotency and why does it matter?
An operation is idempotent if running it repeatedly yields the same result as running it once. Terraform apply is idempotent: re-applying an unchanged config produces “No changes.” This lets you re-run safely in CI without drift or duplicate resources.
Why use Terraform over CloudFormation or scripts?
Terraform is cloud-agnostic (one workflow across AWS, Azure, GCP, and hundreds of providers), uses a readable HCL syntax, and produces an explicit plan before changing anything. Hand-rolled scripts lack a state model and a diff, so they cannot reliably reconcile reality with intent.
Terraform basics
What language does Terraform use?
HCL (HashiCorp Configuration Language), currently HCL2. It is declarative and supports expressions, functions, and types. JSON is also accepted for machine-generated config.
What does a minimal resource look like?
A resource block names a provider type and a local name, then sets arguments.
resource "aws_s3_bucket" "logs" {
bucket = "devcraftly-app-logs"
tags = {
Environment = "prod"
}
}
What is the difference between a resource and a data source?
A resource block manages a real object Terraform creates and owns. A data block only reads existing infrastructure (for example, the latest AMI) so you can reference it without managing it.
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"]
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
}
}
What is a provider?
A provider is a plugin that knows how to talk to a specific API (AWS, Azure, Kubernetes). You declare required providers and configure credentials and region.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
Pin provider versions with
~>so a surprise upgrade does not change behavior between runs. OpenTofu is a drop-in fork and uses the same configuration syntax.
State
What is the Terraform state file?
State (terraform.tfstate) is Terraform’s record of which real resources map to which config blocks, plus their last-known attributes. It is how Terraform builds a diff between desired and actual infrastructure.
Why not store state in Git?
State can contain secrets in plain text, and concurrent edits would corrupt it. Instead use a remote backend (S3, Azure Blob, Terraform Cloud) which centralizes state and supports locking.
terraform {
backend "s3" {
bucket = "devcraftly-tf-state"
key = "prod/network.tfstate"
region = "us-east-1"
dynamodb_table = "tf-locks"
encrypt = true
}
}
What is state locking?
Locking prevents two people from running apply against the same state simultaneously. The S3 backend uses a DynamoDB table; Terraform Cloud locks automatically. Without it, parallel applies can corrupt state.
What is drift?
Drift is when real infrastructure changes outside Terraform (a console edit, an autoscaling action). terraform plan detects it by refreshing state and showing the difference so you can reconcile.
How do you move or rename a resource without destroying it?
Use a moved block (1.1+) so renames don’t force recreation, or terraform state mv for manual surgery.
moved {
from = aws_s3_bucket.logs
to = aws_s3_bucket.app_logs
}
Resources and modules
What is a module?
A module is a reusable, parameterized group of resources. The root directory is itself a module; child modules are called with a module block.
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.8.1"
name = "prod-vpc"
cidr = "10.0.0.0/16"
}
How do variables and outputs work?
Variables parameterize a module’s inputs; outputs expose computed values to the caller or the CLI.
variable "instance_type" {
type = string
default = "t3.micro"
}
output "bucket_arn" {
value = aws_s3_bucket.app_logs.arn
}
What is the difference between count and for_each?
count creates N copies indexed by number; for_each iterates a map or set and keys instances by a stable identifier. Prefer for_each when items can be added or removed, since reindexing under count can destroy and recreate the wrong resource.
resource "aws_iam_user" "team" {
for_each = toset(["alice", "bob", "carol"])
name = each.key
}
Workflow
Walk through the core Terraform workflow.
init downloads providers and configures the backend, plan shows the proposed diff, and apply executes it after confirmation. destroy tears everything down.
terraform init
terraform plan -out=tfplan
terraform apply tfplan
Output:
Plan: 1 to add, 0 to change, 0 to destroy.
aws_s3_bucket.app_logs: Creating...
aws_s3_bucket.app_logs: Creation complete after 2s [id=devcraftly-app-logs]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
What does terraform fmt and validate do?
fmt rewrites files to canonical style; validate checks syntax and internal consistency without contacting any provider API. Both are fast CI gates that run before plan.
What is a workspace?
A workspace is a named, separate state under the same configuration, often used for lightweight environment separation. For meaningful prod/staging isolation, most teams prefer separate backends or directories over workspaces.
Best practices
- Pin Terraform and provider versions, and commit a lockfile so plans are reproducible.
- Always use a remote backend with locking and encryption for shared state.
- Keep modules small and composable; pass configuration in through variables, expose results through outputs.
- Review
terraform planoutput before every apply, and gate applies behind CI. - Never edit state by hand unless necessary; prefer
movedblocks andimportblocks over manualstatecommands. - Mark secrets
sensitive = trueand keep them out of plain-text state by using a real secrets manager.