Explain declarative vs. imperative infrastructure provisioning, and where Terraform fits.
Quick Answer
Imperative tooling (a bash script, boto3 script) specifies the *steps* to reach a result — you must handle ordering, idempotency, and error recovery yourself. Declarative tooling (Terraform, Kubernetes manifests) specifies the *desired end state*, and the tool's engine diffs that against reality and figures out the steps. Terraform is declarative: it builds a dependency graph from resource references, computes create/update/destroy actions via `plan`, and applies them idempotently — running `apply` twice in a row with no config change is a no-op.
Detailed Answer
This distinction comes up constantly when comparing Terraform to shell scripts, SDK-based automation, or CloudFormation, so it's worth having a crisp mental model.
Imperative: specify the steps
An imperative script tells the system exactly how to reach a result, step by step:
aws ec2 run-instances --image-id ami-123 --count 1 --instance-type t3.micro
aws ec2 create-tags --resources i-abcdef --tags Key=Name,Value=web
Problems with this approach at scale:
- You must handle idempotency yourself — running the script twice creates two instances, not one.
- You must handle ordering and error recovery — what happens if step 2 fails after step 1 succeeded?
- There's no built-in way to know what the script has already created without re-reading external state.
Declarative: specify the desired end state
resource "aws_instance" "web" {
ami = "ami-123"
instance_type = "t3.micro"
tags = { Name = "web" }
}
You describe what should exist, not the steps to get there. The engine (Terraform Core) is responsible for:
- Comparing desired state (config) against last-known state (the state file) and real infrastructure.
- Computing the minimal set of create/update/destroy actions needed.
- Executing them in correct dependency order.
- Being idempotent by construction — running
applyagain with no config changes is a no-op, because the diff comes back empty.
Where Terraform sits
Terraform is fully declarative at the resource level: you never write "create this, then that." Its dependency graph, built automatically from resource references, determines execution order, and its plan/apply separation means the "what will change" computation is always visible before anything is touched. This is precisely what makes terraform plan meaningful as a review step — there's a clear notion of "current state" vs. "desired state" to diff, which a purely imperative script doesn't have.
Interview framing: declarative tools answer "what do you want?"; imperative tools answer "what should I do?" — and Terraform deliberately chose the former to get safe, idempotent, reviewable infrastructure changes.