How do you structure Terraform code for multiple environments?
Learn how to structure Terraform for dev, staging, and prod using shared modules, isolated state, and per-environment tfvars to keep changes safe and DRY.
Expected Interview Answer
You structure Terraform for multiple environments by extracting shared infrastructure into reusable modules and giving each environment (dev, staging, prod) its own isolated configuration and state, driven by per-environment variable files so the same code produces safely separated deployments.
The two dominant patterns are a directory-per-environment layout (an env/dev, env/staging, env/prod folder each with its own backend and tfvars, all calling the same modules) and a workspace-based layout (one config with multiple Terraform workspaces switching state). Directory-per-environment is preferred for production because it isolates state files, backends, and blast radius, while workspaces keep code DRY but share a backend and are easy to apply against the wrong environment. Either way, the golden rule is one module definition, many thin environment wrappers that only supply variables.
- Isolated state per environment limits blast radius
- Shared modules avoid copy-paste drift between envs
- Per-environment tfvars make differences explicit
- Promotes changes predictably from dev to prod
- Enables least-privilege credentials per environment
AI Mentor Explanation
Think of one set of official playing conditions (the module) used across the nets, a domestic match, and a Test. Each venue supplies its own pitch, boundary size, and squad list (the tfvars), but nobody rewrites the laws of cricket per ground. Keeping separate scorebooks per match is like isolated state, so a mistake in the nets never corrupts the Test record.
Step-by-Step Explanation
Step 1
Extract shared modules
Move reusable resources (network, cluster, database) into a modules/ directory with input variables and outputs.
Step 2
Create per-environment folders
Make env/dev, env/staging, env/prod, each calling the modules and holding only environment-specific glue.
Step 3
Configure isolated backends
Give each environment its own backend (separate state key or bucket) so state and locking are never shared.
Step 4
Supply per-environment tfvars
Keep dev.tfvars, staging.tfvars, prod.tfvars for sizes, counts, and toggles; the module code stays identical.
Step 5
Scope credentials and promote
Use least-privilege credentials per environment and promote a module version from dev to prod after validation.
What Interviewer Expects
- Knows modules keep code DRY across environments
- Explains state isolation and blast-radius reduction
- Compares directory-per-environment vs workspaces
- Mentions per-environment tfvars and backends
- Understands promotion and least-privilege credentials
Common Mistakes
- Sharing one state file across all environments
- Copy-pasting whole configs instead of using modules
- Relying on workspaces for hard prod isolation
- Hardcoding environment values instead of using tfvars
- Using the same credentials for dev and prod
Best Answer (HR Friendly)
“You write the infrastructure once as reusable building blocks, then give each environment like development, testing, and production its own settings file and its own separate record of what exists. That way changes are consistent everywhere but a mistake in testing can never break production.”
Code Example
# modules/network/main.tf (shared, written once)
variable "cidr" {}
variable "env" {}
resource "aws_vpc" "this" {
cidr_block = var.cidr
tags = { Name = "${var.env}-vpc" }
}
# env/prod/main.tf (thin wrapper)
module "network" {
source = "../../modules/network"
cidr = var.cidr
env = "prod"
}
# env/prod/backend.tf (isolated state)
terraform {
backend "s3" {
bucket = "acme-tf-state"
key = "prod/network.tfstate"
region = "us-east-1"
}
}Follow-up Questions
- When would you choose workspaces over a directory-per-environment layout?
- How do you version and promote a module from dev to prod?
- How do you keep secrets out of your tfvars files?
- How does remote state isolation reduce blast radius?
- How would you enforce that prod applies require manual approval?
MCQ Practice
1. What is the main reason to give each environment its own state file?
Separate state per environment keeps state, locking, and failures isolated, so a mistake in dev cannot damage prod.
2. Which pattern best keeps Terraform code DRY across environments?
Reusable modules are defined once and each environment only supplies variables, avoiding copy-paste drift.
3. A drawback of using Terraform workspaces for prod isolation is that they:
Workspaces switch state within one shared backend, so an operator can easily target the wrong environment.
Flash Cards
Directory-per-environment layout — Separate env/dev, env/staging, env/prod folders, each with its own backend and tfvars calling shared modules.
Why isolate state per environment? — It limits blast radius and locking scope so a failure or bad apply in one env cannot corrupt another.
Role of tfvars in multi-env setups — They hold only environment-specific values (sizes, counts, toggles) while the module code stays identical.
Workspaces vs directories — Workspaces are DRY but share a backend; directories give stronger isolation, preferred for production.
Continue Learning
Related Interview Questions
What is the difference between a root module and a child module in Terraform?
easy
How does terraform destroy work and how do you prevent accidental destruction?
medium
What is Terraform State and Why Does It Matter?
medium
What is the difference between Terraform and configuration tools like Ansible?
medium