If you’ve spent any time in the DevOps space, you’ve almost certainly bumped into both Ansible and Terraform. They’re often mentioned in the same breath, and I regularly see teams debating which one to adopt, as if it were a binary choice.
It isn’t. These tools solve fundamentally different problems, and understanding that distinction is the key to using them well. In this post, I’ll break down what each tool does best, where they overlap, and how I’ve seen them work together in production environments.
Terraform: Infrastructure as Code done right
Terraform, originally by HashiCorp (now under the OpenTofu fork as well), is a declarative Infrastructure as Code tool. You describe the desired end state of your infrastructure in HCL (HashiCorp Configuration Language), and Terraform figures out what needs to change to get there.
What makes Terraform powerful is its state management. It maintains a state file that represents the real-world resources it manages. This means it can compute precise diffs. It knows what exists, what you want, and what needs to happen in between.
A typical Terraform workflow looks like this:
resource "azurerm_resource_group" "example" {
name = "rg-production"
location = "West Europe"
}
resource "azurerm_virtual_network" "example" {
name = "vnet-production"
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
}
You run terraform plan to preview changes, then terraform apply to execute them. If someone manually modifies a resource outside of Terraform, the next plan will detect the drift and propose corrections. That feedback loop is what makes Terraform reliable for infrastructure at scale.
Where Terraform excels
- Cloud resource provisioning. VMs, networks, DNS records, databases, load balancers, IAM roles. Anything your cloud provider exposes as an API, Terraform can probably manage.
- Multi-cloud and hybrid setups. Terraform providers exist for AWS, Azure, GCP, Cloudflare, Kubernetes, and hundreds of other services. You can orchestrate across all of them in a single configuration.
- Dependency resolution. Terraform builds a dependency graph of your resources and creates/destroys them in the correct order.
- Collaboration. With remote state backends (S3, Azure Blob, Terraform Cloud), teams can safely share and lock state, preventing concurrent modifications.
Where Terraform falls short
Terraform is not a configuration management tool. It can provision a VM, but it’s not designed to install packages, manage config files, or restart services inside that VM. You can use provisioners (remote-exec, local-exec), but the Terraform documentation itself discourages them for good reason: they break the declarative model and don’t track state.
Ansible: Configuration management and orchestration
Ansible, maintained by Red Hat, takes a different approach. It’s an agentless automation engine that connects to machines over SSH (or WinRM for Windows) and executes tasks described in YAML playbooks. It’s procedural by nature. You define a sequence of steps, and Ansible runs them top to bottom.
A simple playbook looks like this:
- name: Configure web servers
hosts: webservers
become: true
tasks:
- name: Install nginx
apt:
name: nginx
state: present
- name: Deploy nginx config
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: restart nginx
handlers:
- name: restart nginx
service:
name: nginx
state: restarted
Ansible’s strength is in its simplicity. There’s no agent to install, no central server to maintain (unless you use AWX/Tower), and YAML is easy to read. It’s the Swiss army knife of system administration.
Where Ansible excels
- Configuration management. Installing packages, managing files, enforcing system state across fleets of servers.
- Application deployment. Rolling out code, running migrations, restarting services in a controlled order.
- Ad-hoc tasks. Need to patch 200 servers right now?
ansible all -m apt -a "name=openssl state=latest"handles that in one line. - Network automation. Ansible has strong support for managing network devices (Cisco, Juniper, Arista) that don’t run traditional operating systems.
Where Ansible falls short
Ansible has no built-in state tracking. It doesn’t know what your infrastructure should look like; it just runs tasks. Idempotency depends on using the right modules and writing playbooks carefully. A badly written playbook can be destructive on repeated runs. It’s also slower than Terraform for cloud provisioning since it doesn’t build a dependency graph or parallelize resource creation the same way.
Key differences at a glance
| Aspect | Terraform | Ansible |
|---|---|---|
| Primary purpose | Infrastructure provisioning | Configuration management |
| Approach | Declarative (desired state) | Procedural (step-by-step) |
| Language | HCL | YAML |
| State management | Yes, tracks real-world state | No, stateless by default |
| Agent required | No | No |
| Idempotency | Built-in | Module-dependent |
| Execution model | Plan → Apply (preview before change) | Run tasks immediately |
| Cloud support | Excellent (multi-cloud first) | Good, but secondary to server config |
| Learning curve | Moderate (HCL + state concepts) | Low (YAML + SSH) |
Using them together: the sweet spot
- Terraform provisions the cloud infrastructure: resource groups, virtual networks, VMs, managed databases, DNS records, firewall rules.
- Ansible configures what’s inside: installs packages, deploys applications, manages cron jobs, enforces security baselines.
The handoff usually happens through Terraform outputs. Terraform creates a VM and outputs its IP address, Ansible picks that up (via a dynamic inventory or a generated hosts file) and takes over from there.
Terraform Ansible
──────── ───────
Create VNet ──► Install packages
Create VM ──► Configure services
Create DNS record ──► Deploy application
Output IP addresses ──► Run health checks
This separation keeps each tool focused on what it does best and avoids the anti-pattern of stuffing shell scripts into Terraform provisioners.
When to use what
| Scenario | Recommended tool |
|---|---|
| Provisioning cloud infrastructure from scratch | Terraform |
| Managing server configuration across a fleet | Ansible |
| Multi-cloud orchestration | Terraform |
| Installing and configuring applications on VMs | Ansible |
| Managing infrastructure dependencies and ordering | Terraform |
| Ad-hoc patching or one-off server tasks | Ansible |
| Setting up Kubernetes clusters | Terraform |
| Configuring workloads inside Kubernetes | Ansible or Helm |
Resources
- Terraform documentation
- Ansible documentation
- OpenTofu, the open-source Terraform fork, worth keeping an eye on
Final thoughts
The Ansible vs Terraform debate is a false dichotomy. They’re complementary tools, not competitors. Terraform gives you repeatable, version-controlled infrastructure provisioning with state tracking and drift detection. Ansible gives you powerful, agentless configuration management and ad-hoc automation.
If you’re just starting out, pick the one that solves your most immediate problem. If you’re provisioning cloud resources, start with Terraform. If you’re managing existing servers, start with Ansible. Eventually, you’ll likely end up using both, and your infrastructure will be better for it.