Terraform vs Ansible: Provisioning vs Configuration Management
Basics4 minInnovialabs editorial team
In short
Terraform creates and changes infrastructure (servers, networks, databases, DNS) and tracks it in a state file, while Ansible configures what already exists (packages, files, services); in practice Terraform provisions resources and Ansible makes them ready to run.
The short answer
Terraform answers "what infrastructure should exist": virtual machines, networks, load balancers, managed databases, DNS records, storage buckets. Ansible answers "what should be inside a server": installed packages, nginx configs, users, systemd services, application deployment.
The first is called provisioning, the second configuration management. They are not rivals but two layers of the same job.
Provisioning vs configuration
| Terraform | Ansible | |
|---|---|---|
| Main job | Create, change, delete cloud resources | Configure OS and applications on hosts |
| Style | Declarative: describe the end state | Procedural in form (ordered tasks), idempotent in effect |
| State | Keeps a state file | Keeps no state, checks the host every run |
| How it connects | Provider APIs (AWS, GCP, Azure and others) | SSH (or WinRM) to hosts |
| Language | HCL | YAML playbooks |
| Agent on server | Not needed | Not needed |
State vs stateless
Terraform keeps state: a file mapping your code to the real resources it created. That is why terraform plan can show an exact diff of what will be created, changed and destroyed. Remove a resource from code and Terraform removes it from the cloud.
The price:
- state belongs in a remote backend (S3-compatible storage, Terraform Cloud and similar) with locking, not in your repo;
- state can contain secrets, so access must be restricted;
- manual changes in the cloud console cause drift between code and reality.
Ansible keeps no state. Every run connects to the host and checks: is the package installed? does the file match? If yes, it does nothing. That is idempotency. The downside: Ansible does not know what you removed from a playbook. Delete the task that installs a package and the package stays on the server; you must remove it explicitly with state: absent.
Where they overlap
The line is blurry:
- Ansible has cloud modules and can create virtual machines;
- Terraform has
user_data/cloud-init and provisioners that can run scripts on a server.
You can technically get by with one tool, but it is usually awkward. Without state, Ansible struggles to manage the lifecycle of cloud resources, especially deletion, and Terraform's own documentation treats provisioners as a last resort.
A common workflow using both
- Terraform creates the network, VMs, load balancer, database and DNS.
- Terraform exposes IP addresses via
outputor generates an Ansible inventory. - Ansible connects to the new machines: installs Docker or a runtime, places configs, creates users, enables monitoring agents.
- Application deployment runs in CI/CD, through Ansible or a separate pipeline.
A minimal handoff:
output "web_ips" {
value = aws_instance.web[*].public_ip
}
terraform apply
terraform output -json web_ips | jq -r '.[]' > hosts.txt
ansible-playbook -i hosts.txt site.yml
In container-based setups Ansible's role often shrinks: images are built in CI and servers barely need hand configuration. Still, baseline host preparation (updates, SSH hardening, monitoring agents) is a natural fit for Ansible.
Common mistakes
- Keeping state locally or committing it to git: lost files and conflicts when two people work.
- Editing resources by hand in the console, then being surprised by the Terraform plan.
- Doing all server setup through provisioners: hard to debug and repeat.
- Writing Ansible tasks with
shellandcommandwhere a proper module exists, losing idempotency. - Storing secrets in plain text variables; use Ansible Vault or a secrets manager.
How to choose
- You need to create and destroy cloud resources and review a change plan: Terraform (or its open fork OpenTofu).
- You have a fleet of servers that must be configured the same way: Ansible.
- You have both: use both, with clear boundaries. Terraform owns everything up to "the machine exists", Ansible owns what happens after.