Terraform Best Practices 2026 — Infrastructure-as-Code for Mid-Market Companies

Cloud & DevOps · May 2026 · 14 min read

← Part of the Cloud & DevOps Guide
Emre Yilmaz By Emre Yilmaz · Reepa Solutions

Infrastructure-as-Code is no longer a playground for cloud enthusiasts in 2026 — it is a prerequisite for any serious cloud operation in mid-market companies. Organizations that still provision servers, networks, databases and identities by clicking through a web console pay a fourfold price: no reproducibility, no audit trail, no rollback and no ability to scale across multiple environments. With HashiCorp's license change to the Business Source License in August 2023 and the rise of OpenTofu under the Linux Foundation, the tool landscape has shifted significantly — decisions that seemed obvious three years ago deserve a fresh evaluation in 2026. This article shows what a robust Terraform or OpenTofu setup looks like for mid-market companies, which structures have proven themselves in practice, which anti-patterns you should absolutely avoid, and when a migration to OpenTofu makes sense. For the broader strategic context, see our Cloud & DevOps Guide for Mid-Market Companies.

Why IaC is Mandatory in 2026

Three developments make Infrastructure-as-Code a mandatory discipline in 2026: first, the number of cloud resources that even a mid-market company operates — hybrid cloud landscapes run to four- and five-digit resource counts. Second, regulatory requirements from NIS2, GDPR and ISO 27001 that demand traceable change histories, four-eyes principles and audit logs — ClickOps delivers none of that. Third, the economic reality: without code, environments cannot be cloned, disaster recovery cannot be tested and cost optimisation cannot be automated.

From our consulting practice: a typical mid-market company with 200 to 500 employees that started its cloud migration without IaC now sits on 30 to 60 percent "undocumented ClickOps infrastructure". Remediation costs three to nine months of effort that would have been avoidable with a greenfield start. Four concrete advantages become visible: reproducibility (a new environment in under one hour), versioning (every change in Git, reviewed, reversible), consistency (staging and production from the same code) and scalability (new sites or regions from parameterised modules rather than copy-paste).

Terraform vs OpenTofu vs Pulumi vs CDK — Decision Matrix

The IaC tools market diversified substantially in 2024 and 2025. Four options are relevant for mid-market companies today. The following matrix provides an initial orientation — the final choice depends heavily on team skills, cloud provider mix and existing tooling.

ToolLanguageLicenceStrengthsWeaknesses
TerraformHCLBusiness Source License (HashiCorp)Largest provider ecosystem, mature, broad talent availability, Terraform Cloud as an integrated SaaS platformBSL excludes commercial competing products, vendor lock-in to HashiCorp, HCL as a configuration language has limits for logic
OpenTofuHCLMozilla Public License v2 (Linux Foundation)True open-source licence, highly compatible with Terraform 1.6, broad community support, no provider lock-in risksYounger project, provider ecosystem trails Terraform by a short margin, Terraform Cloud features require third-party solutions
PulumiPython, TypeScript, Go, C#Apache 2.0 (with commercial SaaS)Real programming language with loops, conditions, tests; well-suited for developer teams; native multi-cloud supportSmaller ecosystem, higher entry barrier, operations staff with a pure cloud background find it harder to navigate
AWS CDKTypeScript, Python, Java, GoApache 2.0Very tight AWS integration, generates CloudFormation, well-suited for AWS-only shops with a developer focusAWS-only focus, unsuitable for multi-cloud, CloudFormation as execution layer has its own limits and rollback behaviour

Pragmatic recommendation for mid-market companies: start new projects with OpenTofu, continue existing Terraform setups and migrate as part of planned major releases. Pulumi pays off for strong developer teams that need tests, loops and shared libraries. AWS CDK only when strategically AWS-only, with the awareness that a later cloud migration will replace the IaC code.

Repo Structure: Module Hierarchy, Workspaces, Stacks

Repo structure is the most important architectural decision in an IaC programme — it affects speed, blast radius and review quality on a daily basis. The hierarchy that has proven itself in practice has three levels.

At the lowest level are the modules — reusable building blocks such as "VPC with three AZs", "RDS Postgres with backup policy", "EKS cluster with node groups". Modules are versioned, have clearly defined input variables and output values, and are referenced through a registry. In small setups a Git tag per module version suffices; in larger setups a private Terraform module registry or an S3 bucket with signed module packages is worthwhile.

At the middle level are the stacks — concrete compositions of modules for a specific environment. A stack is the unit that is independently planned and applied, with its own state and its own backend path. Typical stacks are "prod-network", "prod-data", "prod-compute", "staging-network" and so on. Splitting into multiple stacks per environment reduces state size, accelerates `terraform plan` and limits blast radius in case of errors.

At the top level is the repository layout — either a mono-repo in which modules and stacks live together, or a multi-repo setup with separate module repos. For mid-market teams of up to roughly 15 infrastructure engineers, a mono-repo is the calmer choice: a single pull request can carry both a module change and a stack adjustment, reviews are simpler, and refactoring across multiple modules requires no coordination between repos. Multi-repo only pays off when multiple teams independently maintain versions.

A word on Terraform workspaces: they are not intended for environment separation in production setups. Workspaces share backend configuration and variable definitions — an accidental `terraform workspace select` can have catastrophic consequences. For environment separation, separate directories with their own backend blocks are the clean solution; workspaces only for throwaway feature branches or test sandboxes.

Request an IaC audit

Has your Terraform landscape grown organically and you are unsure whether it will hold up for the next two years? We offer a free 30-minute initial consultation — we evaluate repo structure, state setup, module hygiene and migration options toward OpenTofu.

Request a free IaC audit

State Management: Remote Backend, Lock and Encryption

The state is the heart of any Terraform or OpenTofu installation. It contains the complete inventory of all managed resources, their attributes and sometimes secrets in plaintext — such as initial database passwords or connection strings. A production-grade state management setup must meet three requirements.

First, remote backend with state lock. As soon as more than one person plans or applies, a lock mechanism is indispensable — otherwise race conditions arise. Established options: AWS with S3 plus DynamoDB lock, Azure with a storage account and blob lease, GCP with GCS plus object versioning. Terraform Cloud, Spacelift and Scalr provide the same as SaaS with audit trail and RBAC.

Second, encryption and access control. The state bucket must be encrypted (SSE-KMS, CMEK, customer-managed keys), public access blocked, read and write access only through IAM roles — the CI/CD role and a break-glass admin. Direct human access belongs on a small whitelist, not the entire team.

Third, versioning and backups. State files can become corrupted — through parallel operations, provider bugs or failed imports. Bucket versioning with 30 to 90 days retention is the only reliable safeguard.

Module Design: DRY, Versioned, Documented

Modules are the reuse unit in Terraform and OpenTofu. Their design determines whether an IaC programme scales or becomes a maintenance nightmare. Four principles have proven themselves in practice.

For the module registry, two models have become established: an internal Git repo per module with tags and direct source references, or a private Terraform module registry via Terraform Cloud, JFrog Artifactory or GitLab. The public Terraform Registry should never be referenced directly in production setups — always build an internal wrapper that pins the version and sets security defaults.

Variables and Secrets: tfvars, SOPS, Vault

Configuration management in IaC means separating code, configuration and secrets. Code is the HCL definition itself, configuration comprises environment-specific values such as instance sizes or CIDR blocks, and secrets are passwords, API keys and certificates. Three practices implement this separation.

First, tfvars per environment. Each environment gets its own `.tfvars` file (`prod.tfvars`, `staging.tfvars`, `dev.tfvars`) in the repo, containing only non-sensitive configuration. Applied via `terraform apply -var-file=prod.tfvars`. Visible in code reviews, clean audit trail.

Second, SOPS for file-based secrets. When secrets absolutely must reside in the repo (bootstrap credentials, TLS certificates), SOPS with AWS KMS, GCP KMS or age is the clean solution. SOPS encrypts only the values; the diff remains readable. The KMS key permission is the actual protection layer.

Third, secret manager for runtime secrets. Most secrets should not live in the repo but should be read at runtime from AWS Secrets Manager, Azure Key Vault, GCP Secret Manager or HashiCorp Vault. Important: the values still end up in the state — state protection measures apply unchanged.

CI/CD Integration: Atlantis, Terraform Cloud, GitHub Actions, GitLab

Terraform without CI/CD is a three-person setup. Once more than three people are applying changes, a controlled workflow is required — otherwise state-lock conflicts, forgotten plans and inconsistent apply states arise. Four options are well established.

Atlantis is open source and integrates with pull requests from GitHub, GitLab, Bitbucket and Azure DevOps. On every PR, `terraform plan` is run automatically, the result is posted as a PR comment, and the apply only happens after approval and an `atlantis apply` command in the PR. Atlantis is the most straightforward choice when you want to self-host your CI/CD.

Terraform Cloud offers the same as SaaS, plus cost estimation, Sentinel policies, RBAC and an integrated state backend. For mid-market teams without dedicated platform engineers, Terraform Cloud is the fastest starting point — though with BSL licence implications for the underlying Terraform engine.

GitHub Actions and GitLab CI are the generic option — you write a workflow that orchestrates `plan`, `apply` and approval steps yourself. Advantage: maximum flexibility and integration with existing pipeline tooling. Disadvantage: higher initial investment in the workflow itself. This option pays off when you already maintain pipelines for other purposes — see our cluster on CI/CD pipeline setup.

A central principle in all four options: apply permissions for production stacks belong exclusively to the CI/CD identity, not to developer accounts. Anyone who can apply locally bypasses the review workflow — and with it all compliance guarantees.

Drift Detection and Compliance Scans

Even in disciplined teams, drift occurs — through emergency manual edits, through parallel tools like kubectl or cloud CLIs, through provider auto-updates. Three tool categories help detect drift early and automatically block compliance violations.

Checkov (Bridgecrew/Prisma Cloud) checks Terraform code against over a thousand security and compliance rules — encrypted buckets, MFA, tags, open security groups. In pre-commit hooks and CI/CD it blocks problematic PRs before deployment.

tfsec (Aqua Security) pursues the same goal with a different rule focus. Running both in parallel is worthwhile because the rule sets complement each other.

Open Policy Agent (OPA) with Rego allows custom policies — "no RDS outside the EU", "all buckets require a CostCenter tag", "no direct internet access in production". Conftest and Sentinel policies are alternatives.

Drift detection in the strict sense is a daily `terraform plan` run against the production state, with the diff sent to platform owners via Slack, Teams or email. Spacelift, Terraform Cloud and Atlantis offer this as an integrated feature.

Migrating to OpenTofu After the HashiCorp Licence Change

With the switch to the Business Source License in August 2023, HashiCorp changed the rules. The BSL is no longer a true open-source licence — it prohibits commercial use in competing products. In response, OpenTofu was created, a fork under MPL-2, now under the Linux Foundation since 2024.

For most mid-market companies the BSL is not directly problematic — you use Terraform for internal infrastructure. Nevertheless, migrating to OpenTofu has three advantages: eliminating long-term licence risk, protection against unilateral roadmap decisions, and access to new features such as state encryption at rest, which OpenTofu shipped before Terraform.

The migration itself is highly compatible up to Terraform 1.6. OpenTofu reads the same HCL files, the same state files, the same provider configuration. In most cases replacing the binary and running a test against a non-critical stack is sufficient. Problems arise if you have used features that only exist in Terraform Enterprise or Terraform Cloud after 1.6 — Sentinel policies, for example. These must be migrated to alternative solutions such as OPA or Conftest.

Migration plan for 10–20 stacks: week 1 audit, weeks 2–4 incremental rollout with staging tests, week 5 production apply with double review, week 6 cleanup. Risk is low with a disciplined stack-by-stack sequence.

Anti-Patterns to Avoid

The following anti-patterns appear regularly in our audits — they are the primary causes of outages, compliance findings and maintenance nightmares.

Anti-PatternConsequenceCountermeasure
Manual edits in the cloud consoleDrift that is inadvertently rolled back days later by an applyRestrict production IAM tightly, only the CI/CD role may make changes, daily drift detection
No state lockRace conditions, corrupted state files, deleted or duplicated resourcesRemote backend with DynamoDB lock, blob lease or object lock from the start
Monolithic stack with all resourcesPlan times exceeding 20 minutes, high blast radius, blocked teamsSplit into 4 to 8 stacks per environment, clear ownership per stack
Modules without versions, referenced directly from mainStacks break unexpectedly when a module commit changes behaviourStrict semver tags, every stack references a concrete version
Secrets in tfvars in the repoSecrets in the Git history, readable by anyone with repo accessSOPS or secret manager, tfvars only for non-sensitive configuration
Local apply from developer laptopsReview workflow bypassed, missing audit trail, compliance violationsApply permissions exclusively for the CI/CD identity, no personal roles

Reepa IaC Standards

From our audits we have distilled a concise standard that we recommend to mid-market clients as a starting point:

This standard can be adapted to the respective cloud strategy — see our comparison of AWS vs Azure vs GCP for mid-market companies. The GitOps extension with ArgoCD or Flux also builds on a clean IaC foundation — see our cluster on GitOps with ArgoCD and Flux.

Frequently Asked Questions

Should we still invest in Terraform in 2026 or switch to OpenTofu directly?

For new projects, OpenTofu is the safer choice in most cases — the Linux Foundation as steward, a true open-source licence and a growing ecosystem reduce long-term licence risk. Existing Terraform setups with commercial use should be reviewed, because the Business Source License restricts commercial competing products; most mid-market companies are not affected. A migration to OpenTofu is highly compatible up to Terraform 1.6 and feasible in one day per workspace.

Local state or remote backend — what is sufficient for small teams?

A local state on a developer laptop is only acceptable for throwaway experiments. As soon as more than one person plans or applies, a remote backend with state lock is mandatory — otherwise race conditions arise that delete or duplicate resources. For AWS, S3 with DynamoDB lock is the standard; in Azure a storage account with blob lease; in GCP a GCS bucket with object versioning. Terraform Cloud or Spacelift make sense when you additionally need audit trail, approvals and RBAC.

How do you cleanly structure Terraform code for multiple environments?

The clean solution is versioned modules plus a separate stack with its own state for each environment. Workspaces in Terraform are not recommended for environment separation in production setups because they share the same backend path and create blast-radius problems. Instead, use a directory per environment with its own tfvars file and its own backend block; shared building blocks land as modules with a semver tag in an internal registry. This keeps changes scoped to one environment and visible in code reviews.

How do you manage secrets in Terraform cleanly?

Secrets do not belong in tfvars files in the Git repo. The clean solution is separating configuration from secrets: Terraform reads secrets at runtime from a secret manager such as AWS Secrets Manager, Azure Key Vault, HashiCorp Vault, or via SOPS-encrypted files in the repo. It is also important to handle the state itself carefully — the state contains secrets in plaintext, so the state bucket must reside in encrypted storage with restricted permissions and versioning.

How do you prevent drift between Terraform code and the production environment?

Drift typically arises from manual console edits or parallel tools. Three measures are effective: first, scope IAM permissions tightly so that production resources can only be changed through CI/CD roles; second, run automated daily drift detection via `terraform plan` with diff alerting; third, foster a culture in which manual edits are escalated and promptly reflected back in code. Tools like Spacelift, Terraform Cloud and Atlantis offer drift detection as an integrated feature.

Ready to professionalise your IaC landscape?

Let's talk for 30 minutes with no obligation. We assess your current Terraform or OpenTofu maturity, propose a repo layout refactor, and deliver a realistic roadmap for the first 90 days — including a migration path to OpenTofu where it makes sense.

Schedule a 30-minute call
Emre Yilmaz
Emre Yilmaz · DevOps Engineer · Reepa Solutions

IT security and cloud architect with over ten years of experience. Develops Reepa Security with his team — an offensive audit platform for mid-market companies. Writes regularly about cloud security, infrastructure-as-code, NIS2 and GDPR compliance.

Reviewed: 22 May 2026 · More about Emre

More from our knowledge hubs

🛡
Security
Cybersecurity
15 articles →
🧠
Artificial Intelligence
AI for Mid-Market
15 articles →
Infrastructure
Cloud & DevOps
15 articles →
💻
Development
Software Development
15 articles →