Most cloud accounts start the same way. Someone creates a server, a database, and a few security groups in the web console, and it works. Two years later nobody remembers why port 8080 is open, staging differs from production in ways nobody can list, and rebuilding the environment after an incident would take days of guessing. Infrastructure as code fixes this by describing the setup in files that live in Git. Terraform is the most widely used tool for it.
What You Get From Infrastructure as Code
- Every change is a pull request, so you can see who changed what and why, and roll back.
- Staging and production are built from the same code, so they stay alike.
- A new environment for a client or a region takes an hour instead of a week.
- The code is documentation that never goes out of date.
- Security review can happen before a change is applied rather than after an incident.
How Terraform Works
You describe resources such as a VPC, a database, or a DNS record in HCL files. Providers translate those descriptions into API calls for AWS, Google Cloud, Azure, Cloudflare, Kubernetes, and hundreds of other services. terraform plan compares the code with what exists and shows exactly what will be created, changed, or destroyed. terraform apply makes those changes. Terraform records what it manages in a state file, which is how it knows that a resource in the code is the same one that already exists in the cloud.
Treat State as Sensitive and Shared
The default local state file breaks as soon as two people work on the same infrastructure. Move it to a remote backend on day one, such as an S3 bucket, Google Cloud Storage, or Terraform Cloud. Turn on locking so two applies cannot run at once. Since Terraform 1.10 the S3 backend can lock with a lock file in the bucket itself, without a separate DynamoDB table. State often contains secrets such as database passwords in plain text, so encrypt the bucket, enable versioning, and limit who can read it.
Structure Code With Modules and Separate Environments
| Approach | How it works | When it fits |
|---|---|---|
| One directory per environment | envs/staging and envs/production each have their own state and call shared modules with different variables | Most teams. Clear separation, and a mistake in staging cannot touch production state |
| Terraform workspaces | One configuration with several named states selected by terraform workspace select | Many short-lived copies of the same setup, such as preview environments |
| Separate accounts or projects per environment | Each environment also lives in its own cloud account with its own credentials | Production systems where access must be strictly separated |
Put reusable pieces such as a standard VPC, a database with backups and alarms, or a service with its load balancer into modules with clear inputs and outputs. Pin module and provider versions so an upgrade happens on purpose. Keep each state reasonably small. A single state holding everything makes plans slow and every apply risky.
Run Terraform From CI
- 1On each pull request, run terraform fmt -check, terraform validate, and a security scanner such as Checkov or Trivy.
- 2Run terraform plan and post the output as a comment so reviewers see the real effect of the change.
- 3Pay attention to any resource marked for replacement or destruction. A renamed resource can mean a deleted database.
- 4After approval and merge, apply the saved plan from CI, using short-lived cloud credentials through OIDC instead of long-lived access keys.
- 5Block manual changes in the console for production, or at least alert on them.
Bring Existing Infrastructure Under Control
You rarely start from an empty account. Terraform 1.5 added import blocks, and terraform plan -generate-config-out can write a first draft of the configuration for resources you import. Start with low-risk pieces like DNS records and buckets, clean up the generated code, and move on to networks and databases once the team is comfortable. Run plan regularly afterwards. Any difference it reports on code nobody changed is drift from manual edits.
Terraform or OpenTofu?
In 2023 HashiCorp moved Terraform from an open source licence to the Business Source License. The community forked the last open source version as OpenTofu, now maintained under the Linux Foundation. For a company using Terraform to manage its own infrastructure, the licence change usually does not matter. OpenTofu is a reasonable choice if you want an open source licence or a feature it offers, such as built-in state encryption. The two tools still share most syntax and providers, but they are slowly diverging, so pick one per codebase.
If a change to production cannot be reviewed in a pull request, it is one more thing someone has to remember.
We help teams move existing cloud accounts into Terraform without downtime, and our DevOps training includes hands-on Terraform labs with remote state, modules, and CI pipelines.
Key takeaways
- Infrastructure as code turns cloud changes into reviewed, repeatable pull requests.
- Use a remote, encrypted, versioned, and locked backend for state from the first day.
- Separate environments into their own states and share code through versioned modules.
- Review terraform plan in CI and watch for replacements and deletions.
- Import existing resources gradually and run plan regularly to catch drift.


