- Published on
Terraform and Infrastructure as Code: the guide to stop clicking in the console
- Blog

- Henrico Piubello
- Henrico Piubello
- IT Specialist - Grupo Voitto
IT Specialist - Grupo Voitto
- What is Infrastructure as Code and why did it become standard?
- How does the Terraform workflow work?
- Why is state the most delicate part?
- Terraform, OpenTofu, Pulumi or CloudFormation?
- What are the most common Terraform mistakes?
- How do you adopt IaC without stopping the team?
Terraform trades a click in the console for a versioned file: you describe the infrastructure you want, review the change plan and apply. The central gain is not speed — it is knowing exactly what will happen before it happens.
What is Infrastructure as Code and why did it become standard?
Infrastructure as Code means treating servers, networks, databases, queues and permissions as software: defined in files, reviewed in pull requests, versioned in Git and applied by automation. The historical alternative — configuring in the cloud interface — fails for three reasons that show up in any team that grows.
The first is irreproducibility. An environment built by hand cannot be recreated faithfully. When staging and production diverge, the bug that only happens in production becomes routine.
The second is knowledge loss. The configuration lives in the head of whoever clicked. Documentation ages; the interface is the only source of truth and nobody can review it.
The third is the absence of review. Changing a firewall rule in the console is an action with no diff, no approver and no useful history. With IaC, that same change becomes a pull request with an explicit before and after.
Cloud computing made this unavoidable: when every application involves dozens of resources created and destroyed frequently, manual management stops scaling.
Practical example: replicating a hand-built environment into a new region takes days and produces silent divergences. With IaC, it is changing one region variable and applying — the result is identical by construction.
How does the Terraform workflow work?
Terraform is declarative: you describe the final state, not the steps. The tool computes the path by comparing three sources — the code, the state and the reality of the cloud.
The cycle has three commands:
terraform init— reads the configuration, downloads the required providers and connects to the backend where state lives.terraform plan— queries the cloud, compares with the desired state and prints exactly what will be created, changed or destroyed. Nothing happens yet.terraform apply— executes the plan, respecting the dependency graph between resources.
terraform {
required_providers {
aws = { source = "hashicorp/aws", version = "~> 5.0" }
}
backend "s3" {
bucket = "company-tfstate"
key = "production/api.tfstate"
region = "us-east-1"
dynamodb_table = "tfstate-lock"
encrypt = true
}
}
variable "environment" {
type = string
description = "Environment name (dev, staging, prod)."
}
resource "aws_s3_bucket" "uploads" {
bucket = "company-uploads-${var.environment}"
tags = {
Environment = var.environment
ManagedBy = "terraform"
}
}
The plan is the most underrated feature. It turns an infrastructure change into something reviewable: a colleague reads the diff and sees that the "simple tweak" actually destroys and recreates the database. That is the moment the incident is prevented.
Practical example: a team ran plan before changing an RDS instance type and saw must be replaced in the output. The change required recreating the database — discovered in review, not at 3 a.m. with the service down.
Why is state the most delicate part?
State is the inventory linking each resource block in code to the real identifier in the cloud. Without it, Terraform would have no way of knowing the bucket described in the file already exists.
Three rules prevent most incidents:
- State always remote, never in the repository. A local file works for solo work and breaks with the first colleague. It also stores values in plain text — database passwords, keys — and must not be versioned in Git.
- Locking is mandatory. Two simultaneous
applyruns against the same state corrupt the inventory. Backends like S3 with DynamoDB, Terraform Cloud or GCS provide automatic locking. - One state per environment and per domain. A monolithic state holding the whole company turns any change into global risk and makes
planslow. Split by environment (dev/staging/prod) and by area (network, data, applications).
Also worth knowing is drift: someone changed something in the console and reality no longer matches the state. terraform plan detects the divergence and proposes returning to what the code describes. Running the plan periodically in a pipeline is the cheap way to catch that before it becomes a problem.
Practical example: a single state with 4,000 resources made each plan take eleven minutes and blocked the whole team during any apply. Split into six states by domain, it dropped to under a minute and the teams went back to working in parallel.
Terraform, OpenTofu, Pulumi or CloudFormation?
The market has four relevant options with distinct trade-offs:
| Tool | Language | Multi-cloud | License | Best for |
|---|---|---|---|---|
| Terraform | HCL (declarative) | Yes | BUSL (since 2023) | Market standard, largest ecosystem |
| OpenTofu | HCL (compatible) | Yes | MPL 2.0, Linux Foundation | Teams needing a permissive license |
| Pulumi | TypeScript, Python, Go, C# | Yes | Apache 2.0 | Teams that prefer a programming language |
| CloudFormation | YAML/JSON | AWS only | Proprietary, free | AWS-only shops wanting native integration |
The 2023 license change deserves context: Terraform remains free for practically any internal use; the BUSL restricts offering the product as a competing service. For most companies, the practical impact is none. Even so, OpenTofu gained traction by removing the legal uncertainty — and migration is straightforward, since syntax and providers are compatible.
The Pulumi case is different in nature: using a real programming language allows loops, conditionals and abstractions that HCL expresses awkwardly — at the cost of opening the door to the complexity declarativeness was avoiding.
Practical example: a company that only uses AWS and already had teams fluent in CloudFormation would gain nothing by migrating to Terraform. Another, managing AWS, Cloudflare and GitHub, gains a lot: one workflow for all three.
What are the most common Terraform mistakes?
Five patterns show up repeatedly, and all of them have a known fix:
- Running
applyfrom a laptop against production. Without a pipeline there is no review, no history and no version guarantee. Production applies should come from CI/CD, with theplanpublished in the pull request andapplytriggered after approval. - Not pinning versions. A provider without a version constraint means the same configuration can produce different results on different days. Use explicit constraints and version your modules following semantic versioning.
- Secrets in code. Passwords in
.tffiles end up in Git and in the state. Use a secrets manager (Secrets Manager, Vault, SSM) and reference it through a data source. - Abstracting too early. Generic modules created before three real use cases exist become layers that hide what is happening. Duplicate first; abstract when the pattern becomes obvious.
- Ignoring cost. IaC makes it easy to create resources — and to forget them running. Cost estimation tools in the pull request and FinOps discipline keep agility from becoming an invoice.
Practical example: a test environment created by Terraform for a demo stayed up for two months because destroy was never run. The fix was trivial and structural: scheduled terraform destroy in a pipeline for ephemeral environments.
How do you adopt IaC without stopping the team?
An incremental path that does not require migrating everything:
- Start with a new environment, not the legacy one. Writing Terraform for existing infrastructure requires importing resources one by one — laborious and risky as a first contact.
- One small, complete project. A bucket, a function, a DNS record. Go through the full cycle: code, remote backend, reviewed plan, apply via pipeline.
- Structure it from the start.
main.tf,variables.tf,outputs.tfand one directory per environment. A simple convention that avoids a painful reorganization later. - Put the
planin the pull request. This is the step that converts the team: when people see the infrastructure diff in review, resistance usually ends. - Then expand to legacy by domain. Start with what changes frequently — network rules, permissions — and leave the stable parts for last.
In larger organizations, that path naturally meets platform engineering: ready-made Terraform modules become the building blocks a product team consumes without needing to understand the cloud underneath. And when the target is container orchestration, the usual combination is Terraform creating the cluster and versioned manifests describing what runs inside it — the pattern detailed in the Kubernetes guide.
Practical example: a team started with a single bucket in Terraform and a plan pipeline. Three months later, the entire network and all permissions were versioned — with no formal "migration project", just converting whatever was going to be changed anyway.
Conclusion
Infrastructure as Code solves a problem that is not about automation but about governance: making changes to critical environments explicit, reviewable and reproducible. Terraform became the standard for that practice by combining a simple declarative model with a provider ecosystem covering practically everything with an API — and the plan, which shows the future before it happens, is on its own the biggest reason to adopt it. The caveats are well known and have recipes: remote state with locking, pinned versions, secrets outside the code, applies through a pipeline and vigilance over cost. On licensing, the BUSL does not affect internal use at most companies, and OpenTofu is there as a compatible alternative for anyone needing legal certainty. Start small, in a new environment, and let the plan in the pull request convince the team of the rest.
## faq
Frequently asked questions
What is Infrastructure as Code (IaC)?
It is the practice of defining and provisioning infrastructure — virtual machines, networks, databases, permissions, DNS — through versioned configuration files instead of manual configuration in consoles or improvised scripts. The environment becomes reproducible: the same code produces the same result in development, staging and production.
What is Terraform and how does it work?
Terraform is an IaC tool created by HashiCorp that reads declarative files written in HCL, compares what is described with what actually exists in the cloud and computes the minimal set of operations to reconcile the two. The workflow is init (download providers), plan (show what will change) and apply (execute).
What is the difference between Terraform and Ansible?
Terraform provisions resources — it creates the machine, the network, the database. Ansible configures what already exists — installing packages, adjusting files, starting services. They are complementary: it is common for Terraform to create the infrastructure and Ansible to configure what runs inside it, although containers have significantly reduced the need for the second step.
What is Terraform state and why does it matter so much?
The state is the file that maps each resource described in code to the real resource identifier in the cloud. Without it, Terraform would not know what it has already created and would treat everything as new. That is why it must live in a remote backend with locking and versioning — S3 with DynamoDB, Terraform Cloud, GCS or equivalent — and never in the repository, since it usually contains sensitive values in plain text.
Is Terraform still open source?
Not in the strict sense. In August 2023 HashiCorp moved from the MPL 2.0 license to the Business Source License (BUSL), which restricts competing use. In response, the community created OpenTofu, a fork maintained by the Linux Foundation under MPL 2.0, compatible with Terraform syntax and providers.
Does Terraform work with any cloud?
It works with practically any service that has an API, through providers — AWS, Azure, Google Cloud, Oracle, Cloudflare, GitHub, Datadog, Kubernetes and hundreds of others. But the code is not portable between clouds: resources are provider-specific. What Terraform standardizes is the workflow, not the architecture.
Topics in this article
## continue lendo
Artigos relacionados
Keep browsing
Previous article

Next.js: the React framework for production applications
Next.js solves routing, rendering and caching for React. See the App Router, Server Components, rendering strategies and when it is not worth it.
Read moreNext article

n8n: AI workflow automation you can host yourself
n8n connects APIs, databases and AI models in visual flows with code when needed. See how it works, the real cost and when it beats Zapier and Make.
Read moreAbout the author



