Article

Pragmatic Terraform for Teams of 5 to 50 Engineers

How to adopt Infrastructure as Code without turning it into a second product your team has to maintain. Sequencing, module discipline, and the failure modes to avoid.

If you lead an engineering organization of five to fifty engineers, Terraform is probably already in your stack — or on the roadmap because someone said “we should have Infrastructure as Code.” The question worth your attention is not whether to adopt it. It is how much of it to adopt, in what order, and what it will cost your team to maintain.

I have implemented Terraform in very different settings: a Salesforce DevOps platform at Copado with custom modules across GKE, Cloud Storage, and Cloud SQL; a globally available platform for Telefónica Foundation with eight autoscaling groups and three high-availability clusters; and smaller freelance engagements where the entire platform team was two people. The failures I have seen were almost never caused by Terraform itself. They were caused by adopting more of it than the team could carry.

The common mistake: modeling everything on day one

Terraform adoptions fail through excess more often than through neglect. A motivated engineer discovers modules, workspaces, and wrapper tooling, and within a month the team has an abstraction layer that models the entire company — environments, accounts, naming conventions, a module registry — before a single production workload runs through it.

The cost of this shows up six months later:

  • Changes that should take ten minutes take a day, because they touch three layers of module indirection.
  • Only the original author understands the structure. Everyone else copies existing examples and hopes.
  • The team starts making “just this once” changes in the console, and the code drifts away from reality.

That last one is the real failure condition. Terraform that no longer matches the actual environment is worse than no Terraform: it gives you false confidence in a description of infrastructure that does not exist.

What a right-sized adoption looks like

The sequencing that has worked across my engagements is boring and incremental:

First: the resources that hurt when they drift. Networking, IAM, DNS, databases. These change rarely, break loudly, and benefit most from review before apply. Start here even if everything else stays manual for a while.

Second: the environments you create repeatedly. If your team spins up staging or preview environments, that is where IaC pays back fastest — the same definition, applied many times, is Terraform’s best case.

Third: the application layer, only where it earns its place. Not everything belongs in Terraform. Deployment of application versions usually belongs in your CI/CD pipeline, not your infrastructure repo. Mixing the two couples every release to an infrastructure change and slows both down.

Modules: extract, don’t design. Write plain resources first. When the same pattern appears a third time, extract a module from the working examples. Modules designed in advance for imagined reuse are the primary source of the indirection problem above. A small team needs perhaps five to ten modules, not a registry.

State: managed backend, one state per blast radius. Remote state with locking (S3 + DynamoDB, GCS, Terraform Cloud) is non-negotiable from day one. Split state so that a mistake in one area cannot destroy another — per environment at minimum, per domain (network / data / compute) as you grow. A single monolithic state file is the difference between a bad afternoon and a bad week.

The organizational side, which matters more

The technical decisions above are recoverable. The organizational ones are harder to retrofit:

Apply happens in CI, not on laptops. The moment terraform apply runs from an engineer’s machine, you have unauditable changes and state conflicts waiting to happen. A simple pipeline — plan on pull request, apply on merge, with the plan output visible in review — is achievable in a day with GitHub Actions and changes the discipline of the whole team. In one freelance engagement, moving a client to exactly this model cut deployment time by roughly 40% and eliminated the manual environment errors that had been generating incidents.

The console becomes read-only, culturally if not technically. You will not block console access on day one, and emergency changes will happen. What matters is the norm: changes go through code, and console interventions get backported the same week. Drift detection (terraform plan on a schedule) makes violations visible instead of silent.

Someone owns the codebase. Not full-time — but a named person who reviews structure, prunes dead code, and decides when a module is worth extracting. Terraform repositories without an owner accumulate copy-paste at the same rate application code does.

What it costs

Be honest with your leadership team about the investment. For a team in this size range, expect:

  • Two to six weeks of focused effort to bring the core infrastructure under management, depending on how much history the environment carries.
  • A permanent tax of code review on infrastructure changes — which is the point, but it is still time.
  • A learning curve for every engineer who touches it. Terraform is not hard, but state, plan semantics, and module composition take a few weeks of practice.

Against that: reproducible environments, reviewable changes, an audit trail, and the ability to recover or replicate your platform from code. For most teams past ten engineers, the balance tips clearly in favor — provided the scope stays disciplined.

When this applies, and when it does not

This advice fits teams of roughly five to fifty engineers running on AWS, GCP, or Azure with a platform that changes weekly rather than hourly.

It does not fit two cases. If you are a two-person startup iterating on product-market fit, full IaC coverage is premature — manage the risky resources (IAM, DNS, data) and defer the rest. And if you are a large enterprise with a platform team of twenty, you need the layered structure this article warns against — at that scale the indirection pays for itself, and you should be looking at Terragrunt, policy as code, and a proper module registry.

If you are considering this

The cheapest way to get this right is to sequence it correctly from the start; the most expensive is to unwind an over-built adoption a year in. I do both kinds of engagement — greenfield IaC adoption and rationalizing an existing codebase — as fixed-scope contract work. Details on the Infrastructure as Code and Automation page.