One Codebase, One State File, All Tenants
The simplest approach is to define all tenants in a single Terraform configuration and loop over a shared module. Think of it like a spreadsheet: you have one sheet, and each row is a tenant. You can see everything at once, and adding a new tenant is as simple as adding a new row.
In Terraform, this looks like a for_each over a map of tenant configurations, keyed by tenant name, each value carrying that tenant's size and region. A single module call with that for_each instantiates the tenant-stack module once per map entry — one VPC, one set of subnets, one RDS instance, one set of IAM roles, per tenant. Adding a new tenant is a one-line change to the tenants variable — a new map entry, nothing else. You can see the state of all tenants with a single terraform show. For small tenant counts (under ~50), this is genuinely convenient.
The Trade-offs
Pros:
- Simple to understand and operate. One terraform apply touches everything.
- Easy to audit: the entire platform's desired state is in one place.
- Adding a tenant requires a one-line config change.
Cons — The Monolith Risk:
- State file bloat: With 500 tenants, each with 30+ resources, your state file contains 15,000+ resource records. terraform plan can take 15–30 minutes as Terraform refreshes every resource against the cloud provider's API.
- Shared fate / shared blast radius: If the apply fails halfway through (say, Tenant 250's RDS instance hits a quota limit), Terraform holds the state lock. No other changes can be made until the error is resolved. A bug in the module affects every tenant simultaneously.
- Dangerous deletions: Removing a tenant from the map causes Terraform to plan destruction of all their resources. A typo in the variable file could accidentally queue the deletion of a paying customer's entire infrastructure.
Interviewers often ask: "How would you handle a Terraform state file that's become too large and slow?" The answer involves state decomposition — splitting one large state into multiple smaller ones, either by environment, by tenant, or by infrastructure layer. The terraform state mv command can migrate resources between state files, but it requires careful planning and a maintenance window. Mention that this is a common scaling pain point with the module-per-tenant pattern.