Terraform is an infrastructure as code tool that lets engineers declare cloud and on-premises resources in text files and then creates, changes and destroys them through provider APIs to match that declaration. Introduced by HashiCorp in 2014, it became the most widely used multi-cloud provisioning tool, managing everything from networks and virtual machines to DNS records, Kubernetes clusters and SaaS settings.
Terraform is declarative: a configuration describes the desired end state, not the steps to reach it. The tool compares that description with a recorded state file and with reality, computes a plan of the necessary changes and applies them in dependency order, which makes infrastructure reviewable, repeatable and version-controlled like application code.
How Terraform turns configuration into infrastructure
Terraform reads configuration written in HashiCorp Configuration Language (HCL), builds a dependency graph of all resources and walks that graph to decide what to create first. A subnet that references a network, for example, is created only after the network exists, while independent resources are processed in parallel, ten at a time by default.
The standard workflow has a small number of commands, each with a distinct role, as summarized below.
| Command | What it does | Changes infrastructure |
|---|---|---|
| terraform init | Downloads providers and modules, configures the backend | No |
| terraform validate | Checks syntax and internal consistency | No |
| terraform plan | Compares config, state and reality, shows the diff | No |
| terraform apply | Executes the plan after confirmation | Yes |
| terraform destroy | Removes every resource managed by the configuration | Yes |
| terraform import | Brings an existing resource under management | No, it updates state only |
The plan is the safety mechanism of Terraform. It marks each resource as created, updated in place, replaced or destroyed, and reviewers should pay special attention to replacement, because changing an immutable attribute, such as the name of some database instances, deletes the old resource and creates a new one.
Providers, modules and state
Terraform itself knows nothing about any cloud. Providers are plugins that translate resource definitions into API calls, and thousands exist for public clouds, virtualization platforms, network devices and SaaS products. Modules package reusable groups of resources behind input variables and outputs.
| Building block | Purpose | Example |
|---|---|---|
| Provider | Plugin that talks to a platform API | A public cloud or DNS provider |
| Resource | One managed infrastructure object | A virtual network or storage bucket |
| Data source | Read-only lookup of existing objects | The latest approved machine image |
| Variable and output | Inputs and exported values | Region name, load balancer address |
| Module | Reusable, versioned group of resources | A standard three-tier network |
| Backend | Where state is stored and locked | Object storage with locking |
State maps each resource in the configuration to a real object ID and caches its attributes. It is essential, because without it Terraform cannot tell which existing objects it owns. State must be stored in a remote backend with locking so that two engineers cannot apply at the same time, and it must be protected as a secret, because it often contains passwords and keys in plain text.
Terraform compared with other infrastructure tools
Terraform is one of several infrastructure as code tools, and the main differences lie in language, scope and how they track state. The comparison below includes its closest neighbors.
| Tool | Model | Main strength | Main limitation |
|---|---|---|---|
| Terraform | Declarative HCL, external state | Multi-cloud, huge provider ecosystem | State management, source-available license |
| OpenTofu | Declarative HCL, external state | Open-source fork, compatible workflow | Divergence from Terraform over time |
| Ansible | Procedural tasks, mostly stateless | Configuring software inside servers | Weaker drift detection for cloud resources |
| Cloud-native templates | Declarative JSON or YAML | Deep integration with one cloud | Locked to a single provider |
| Pulumi | Declarative engine, general-purpose languages | Loops and tests in familiar languages | More freedom, more room for complexity |
In 2023 HashiCorp moved Terraform from the Mozilla Public License to the Business Source License, which restricts competing commercial use. The community responded with OpenTofu, an open-source fork that keeps the same language and workflow, so organizations now choose between the two on licensing and feature grounds.
Structuring Terraform for teams
Terraform works well for one person and one environment almost by default; at team scale it needs structure. The key decisions concern how state is split, how changes are reviewed and how versions are pinned.
| Situation | Recommended practice | Reason |
|---|---|---|
| Several environments | Separate state per environment | A mistake in test cannot touch production |
| Large estate | Split state by component or team | Faster plans, smaller blast radius |
| Shared patterns | Versioned internal modules | Consistency without copy and paste |
| Many contributors | Plan in CI, apply after review | Every change is visible and approved |
| Provider upgrades | Pin versions and commit the lock file | Reproducible runs across machines |
Running Terraform from a pipeline instead of laptops also centralizes credentials, records who applied what and allows policy as code checks, for example rejecting public storage buckets before they are created.
Common Terraform pitfalls
Most Terraform incidents result from state problems, manual changes or unreviewed plans. The following pitfalls appear repeatedly in real projects.
- Configuration drift: manual console edits make reality diverge from code, and the next apply may silently revert them.
- Local state files: state on a laptop is easily lost or overwritten and cannot be locked for the team.
- Secrets in state and code: sensitive values marked as sensitive are hidden in output but still stored in state.
- One giant root module: thousands of resources in one state make every plan slow and every mistake large.
- Applying without reading the plan: an unnoticed replacement of a database or volume can mean data loss.
- Unpinned providers: a new major provider version can change resource behavior between two runs.
In simple terms
Terraform is like a written blueprint for computer infrastructure. Instead of clicking through web consoles to create servers, networks and databases, an engineer writes down what should exist, and Terraform builds it.
Before changing anything, Terraform shows a preview of exactly what it will add, change or remove, much like an architect showing renovation plans before the builders arrive. Because the blueprint is a text file, it can be reviewed, copied for a new office or restored after a disaster.
A practical example
A software company runs its product in one cloud region and must add a second region for a large customer with data residency requirements. The original environment was built by hand over three years, and nobody is sure which of its roughly 400 resources are still needed.
The platform team first imports the existing network, databases and load balancers into Terraform and refactors them into modules for networking, compute and data. Each region becomes a small root configuration that calls those modules with its own variables and keeps its own remote state. Every change runs a plan in the CI pipeline, and a second engineer approves it before apply.
Building the new region then takes about one day of review instead of an estimated six weeks of manual work. The two regions stay identical by design, and the next audit uses the reviewed pull requests as a complete change history.