Terraform vs Ansible comes down to one split. Terraform builds infrastructure and keeps a state file of what it built. Ansible configures machines and network devices that already exist, over SSH, with no agent to install. Network engineer? Learn Ansible first. Heading into cloud? Learn Terraform first. Most teams end up running both.
That’s the short version. Below, we put both tools on the same small lab, four switches and three VLANs, and looked at what each one does on the first run, the second run, and the day someone deletes something. The difference that matters shows up on day two. And it’s not the one most comparisons spend their time on.
Terraform vs Ansible: what’s the difference?
Terraform is an infrastructure as code tool for provisioning. You describe what should exist (a VM, a subnet, a VLAN) and Terraform creates, changes or destroys real objects until they match. Ansible is an automation tool for configuration. You write tasks (install a package, push a config line, restart a service) and Ansible runs them against the hosts in your inventory.
| Terraform | Ansible | |
|---|---|---|
| Main job | Create and remove infrastructure | Configure what already exists |
| Language | HCL | YAML playbooks |
| Style | Declarative: you describe the end state | Mostly procedural: tasks run in the order you wrote them |
| State | A state file tracks everything it manages | No state file. It checks the target on every run |
| Agent on targets | None. It talks to provider APIs | None. SSH, PowerShell remoting and other transports |
| Python on targets | Not needed | Linux targets need it. Network devices don’t |
| Network devices | Through providers, like Cisco’s IOS XE provider over NETCONF | Through collections, like cisco.ios over CLI and SSH |
| Runs on Windows | Native Windows builds | The control node needs WSL |
| Licence | Business Source License (BUSL) since 1.6.0 | GPL-3.0 |
| Owner | IBM, through HashiCorp | IBM, through Red Hat |
| Latest release (2026-10-19) | 1.16.6 | ansible-core 2.21.5 |
| Certification | HashiCorp Terraform Associate (004) | Red Hat Certified Engineer in Ansible |
Is Terraform declarative and Ansible procedural?
Mostly, yes. HashiCorp’s own docs say the Terraform language “is declarative, describing an intended goal rather than the steps to reach that goal.” Ansible gets called procedural because a playbook runs top to bottom, in the order you wrote it.
The line blurs inside a single task, though. Ansible’s network resource modules, like cisco.ios.ios_vlans, take a description of the VLANs you want and work out the commands themselves. So one task behaves declaratively. A whole playbook is still a list of steps.
Why does Terraform’s state file matter so much?
It’s Terraform’s memory. HashiCorp’s docs say Terraform “destroys resources that exist in the state but no longer exist in the configuration.” Ansible has nothing like that. It knows what you asked for on this run and what the device looks like right now. It doesn’t know what it did last Tuesday.
Sounds abstract? The lab below makes it concrete.
Terraform vs Ansible on the same lab: what actually happens?
Here’s the setup. Four Catalyst 9000v switches, sw1 to sw4, in EVE-NG or Cisco Modeling Labs. You want VLAN 10 (USERS), VLAN 20 (VOICE) and VLAN 30 (PRINTERS) on every switch. One Linux control node runs both tools. If you don’t have a lab yet, our home lab setup guide for network engineers gets one running.
How we checked it, so you know what’s real. Terraform 1.16.6 ran a real first terraform plan on this config with Cisco’s IOS XE provider (version 1.1.1). The later Terraform rows come from Terraform’s built-in terraform_data resource standing in for the switches, plus the provider’s source code. The Ansible side ran the cisco.ios collection’s own code (version 11.6.0) in check mode against a simulated show vlan, the same way the collection’s unit tests do. No live switch was involved, so treat every output block below as representative.

Same control node, same four switches, two transports. Terraform’s IOS XE provider talks NETCONF over SSH on TCP 830 and needs netconf-yang on each switch. Ansible’s network_cli sends plain CLI over SSH on TCP 22.
The Terraform version
Cisco’s provider talks NETCONF over SSH, on port 830 by default. So each switch needs one line before Terraform can reach it:
netconf-yang
Then the config. setproduct pairs every switch with every VLAN, so 4 switches times 3 VLANs gives 12 resources:
terraform {
required_providers {
iosxe = {
source = "CiscoDevNet/iosxe"
version = "1.1.1"
}
}
}
provider "iosxe" {
username = "admin"
password = var.switch_password
devices = [
{ name = "sw1", host = "10.10.10.11" },
{ name = "sw2", host = "10.10.10.12" },
{ name = "sw3", host = "10.10.10.13" },
{ name = "sw4", host = "10.10.10.14" },
]
}
variable "switch_password" {
type = string
sensitive = true
}
locals {
switches = ["sw1", "sw2", "sw3", "sw4"]
vlans = { "10" = "USERS", "20" = "VOICE", "30" = "PRINTERS" }
# one entry per switch and VLAN pair: 4 x 3 = 12
pairs = {
for p in setproduct(local.switches, keys(local.vlans)) :
"${p[0]}-vlan${p[1]}" => { device = p[0], vlan_id = p[1] }
}
}
resource "iosxe_vlan" "lab" {
for_each = local.pairs
device = each.value.device
vlan_id = each.value.vlan_id
name = local.vlans[each.value.vlan_id]
}
On a fresh lab, terraform plan lists all 12 and sums them up:
# iosxe_vlan.lab["sw1-vlan10"] will be created
# iosxe_vlan.lab["sw1-vlan20"] will be created
...
# iosxe_vlan.lab["sw4-vlan30"] will be created
Plan: 12 to add, 0 to change, 0 to destroy.
You read that plan before anything touches a switch. That’s the habit Terraform teaches, and honestly it’s worth learning for its own sake.
The Ansible version
The inventory tells Ansible these are Cisco IOS devices reached over CLI and SSH:
switches:
hosts:
sw1: { ansible_host: 10.10.10.11 }
sw2: { ansible_host: 10.10.10.12 }
sw3: { ansible_host: 10.10.10.13 }
sw4: { ansible_host: 10.10.10.14 }
vars:
ansible_connection: ansible.netcommon.network_cli
ansible_network_os: cisco.ios.ios
ansible_user: admin
The playbook is one task:
- name: Lab VLANs on all four switches
hosts: switches
gather_facts: false
tasks:
- name: Make sure VLANs 10, 20 and 30 exist
cisco.ios.ios_vlans:
config:
- vlan_id: 10
name: USERS
- vlan_id: 20
name: VOICE
- vlan_id: 30
name: PRINTERS
state: merged
On a switch with none of these VLANs, the module turns that into six CLI lines:
vlan 10
name USERS
vlan 20
name VOICE
vlan 30
name PRINTERS
And the recap at the end of the first run looks like this (representative):
PLAY RECAP *********************************************************************
sw1 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
sw2 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
sw3 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
sw4 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
One task per switch, so ok=1. A changed task counts as ok too, which looks odd the first time you see it.
Notice what the switches didn’t need. No Python, no NETCONF, no agent. Ansible’s network modules run on the control node and send plain CLI over SSH. Keep that in mind for later.
What changes on run two, after drift, and after you delete VLAN 30?
Here’s where it gets interesting.
| What you do | Terraform | Ansible (state: merged) |
|---|---|---|
| Run it again, nothing changed | No changes. Your infrastructure matches the configuration. | changed=0 on all 4 switches |
Someone types no vlan 30 on sw2 | Plan shows 1 to add. VLAN 30 comes back on sw2 | sw2 shows changed=1 and gets vlan 30 and name PRINTERS again. The other 3 stay at changed=0 |
| You delete VLAN 30 from your code | Plan: 0 to add, 0 to change, 4 to destroy. VLAN 30 leaves all 4 switches | changed=0. VLAN 30 stays on all 4 switches |
| VLANs left on the 4 switches | 8 | 12 |
The first two rows are a draw. Both tools are idempotent, and both put a hand-deleted VLAN back on the next run.
The third row is the whole debate in one line. Terraform remembers it created VLAN 30 on four switches, so taking it out of the code takes it off the network. Ansible’s merged state only adds what you list. Remove VLAN 30 from the list and Ansible just stops mentioning it. You’re left with four VLAN 30s that nobody’s code describes any more.
Is that a bug? No. It’s the design. Ansible keeps no record of what it did, so it can’t know VLAN 30 was its idea.

Delete VLAN 30 from your code. Terraform plans 4 to destroy and leaves 8 VLANs across the 4 switches. Ansible’s merged state reports changed=0 and leaves all 12, including 4 orphan copies of VLAN 30.
So how does Ansible remove a VLAN?
You ask it to, explicitly. The ios_vlans module has several states, and they don’t all do what their names suggest. Here’s what each one planned in our check-mode runs against cisco.ios 11.6.0:
purged, with VLAN 30 listed, sendsno vlan 30. That’s the clean removal.deleted, with VLAN 30 listed, doesn’t remove the VLAN at all. It sendsno name PRINTERS,no state activeandshutdown. VLAN 30 stays, nameless and shut down.overridden, with only VLANs 10 and 20 listed, removes VLAN 30. But list only the names and it also sendsshutdownunder VLANs 10 and 20, because overridden resets every attribute you leave out. Addstate: activeandshutdown: disabledto each VLAN and that goes away. It also triesno vlan 1andno vlan 1002to1005. Ansible’s own docs example shows that sameno vlan 1line, with VLAN 1 still there afterwards.

In check mode against cisco.ios 11.6.0, purged sent no vlan 30. deleted sent no name PRINTERS, no state active and shutdown, so VLAN 30 stayed on the switch.
Ansible’s documentation is blunt about overridden: “Use caution with this state as you could remove your access to the device.” So here’s the rule. Run any state other than merged with --check first, read the commands, then run it for real.
Terraform vs Ansible: which comes first on your track?
It depends on the exam and the job you’re aiming at. Here’s the rule we’d give a friend.
| You are | Learn first | First exam that tests it |
|---|---|---|
| Network engineer, CCNA level or heading for CCNA Automation | Ansible | CCNA Automation (200-901) |
| Cloud or platform engineer, AWS or Azure | Terraform | HashiCorp Terraform Associate (004) |
| Linux admin | Ansible | Red Hat Certified Engineer in Ansible (EX200 + EX294) |
| Not sure yet | Ansible | None needed yet |
Why Ansible when you’re unsure? It works against things you already have, like a Linux VM or a lab switch. Terraform needs something to create things in, like a cloud account or a platform with a provider, before it’s useful.

Network track: Ansible first, and CCNA Automation (200-901) asks you to read playbooks. Cloud track: Terraform first, with Terraform Associate (004) as the first exam. Linux admins follow the network path.
Network engineers: start with Ansible
Three reasons, and you can check every one of them.
- Your exam reads Ansible. The CCNA Automation (200-901) exam topics give Infrastructure and Automation 20% of the exam. Objective 5.6 asks you to describe “the capabilities of automation tools such as Ansible, Terraform, and Cisco NSO.” Objective 5.8 goes further for one of them: “Interpret the workflow being automated by an Ansible playbook.” Terraform gets a description. Ansible gets read line by line.
- It works on the gear in your lab today. Ansible’s network modules run on the control node, and the most common connection is CLI over SSH. The switch needs SSH and nothing else.
- Terraform asks more of the device. Cisco’s IOS XE provider uses NETCONF, so every switch needs
netconf-yangand an IOS XE release. The provider’s own README lists Catalyst 8000v 17.15.3 and Catalyst 9000v 17.15.1 as the tested releases. If your lab runs older images, check NETCONF support before you plan around Terraform.
Once a static inventory gets painful, build a NetBox dynamic inventory for Ansible. Add the scripting side with 10 Python scripts for Cisco devices and our guide to the Python automation skills behind 200-901. Then add Terraform. Thinking about it as a career move? Our network automation engineer salary guide shows which skills pay.
Cloud and platform engineers: start with Terraform
If your work means creating cloud resources (networks, subnets, instances, managed databases), Terraform is built for exactly that job. The first exam is short and cheap. HashiCorp’s Terraform Associate (004) costs $70.50 USD plus tax, runs one hour, is multiple choice and online proctored, tests Terraform 1.12, and stays valid for two years.
Its objectives double as a study plan: providers, the init, plan, apply and destroy workflow, state and drift, modules, and HCP Terraform. Keep our Terraform commands cheat sheet open while you practise.
Linux admins: start with Ansible
Red Hat’s automation credential is now called Red Hat Certified Engineer in Ansible. It takes two exams: EX200, the RHCSA, and EX294, which Red Hat titles the “Red Hat Certified Advanced System Administrator in Ansible exam.” EX294 is hands-on. You write playbooks, and Red Hat checks the result on freshly installed systems.
That’s a bigger lift than a one-hour multiple-choice test. But if you already run Linux boxes, Ansible pays off on day one, and this path builds straight on the RHCSA you may already be studying for. When you can write a playbook without looking things up, test yourself with our 120 Ansible interview questions.
When to use Ansible vs Terraform
Here’s the one-line test. Use Terraform when something needs to exist. Use Ansible when something that exists needs to change. In practice:
- Provisioning on AWS or Azure: Terraform. It plans the change, shows you the count, and tracks what it built.
- Configuring servers after they boot: Ansible. Packages, users, files and services are its home turf.
- Network automation on existing switches and routers: Ansible, for most labs and brownfield networks. Terraform when your platform has a solid provider and you want the network in the same plan-and-apply workflow as your cloud.
- Homelab VMs, on Proxmox or anywhere else: both. Terraform creates the VMs, Ansible sets them up. Our Proxmox vs Docker comparison helps you pick the platform underneath.
- One-off fixes across many hosts: Ansible. An ad hoc command or a short playbook beats writing infrastructure code for a five-minute job. Our Ansible ad hoc commands cheat sheet lists them.
Can each tool do the other’s job? A bit. Ansible has cloud modules that create instances, and Terraform has provisioners that run commands on a new machine. HashiCorp itself says you “should exhaust all alternatives before using provisioners.” Take the hint.
Can you use Terraform and Ansible together?
Yes, and it’s the most common pattern: Terraform builds, Ansible configures. The hard part used to be the handoff. Terraform knows the new machines’ IP addresses, and Ansible needs them in an inventory.
How does the Terraform Ansible provider work?
The Terraform Ansible provider (ansible/ansible, version 1.5.0) closes that gap. It gives Terraform four resources: ansible_host, ansible_group, ansible_playbook and ansible_vault. Register each new machine as a host:
resource "ansible_host" "web" {
name = aws_instance.web.public_ip
groups = ["web"]
variables = {
ansible_user = "ubuntu"
}
}
Then point Ansible at Terraform’s state with the cloud.terraform collection’s inventory plugin. Save this as terraform_provider.yml:
plugin: cloud.terraform.terraform_provider
Run ansible-playbook -i terraform_provider.yml site.yml from the Terraform project directory, and every host Terraform created shows up in the right group. No IP addresses copied by hand.

Terraform builds the machine and records it as an ansible_host resource. The cloud.terraform inventory plugin reads that from state, so Ansible configures the right hosts without a hand-written inventory.
How do Terraform and Ansible compare to CloudFormation, Kubernetes, Puppet and Chef?
Terraform vs CloudFormation
AWS CloudFormation is AWS’s own provisioning service. You write a template, and AWS creates the resources as a stack that you can update or delete as one unit. It’s built around AWS resources. Terraform does the same job through providers, so one workflow covers AWS, Azure and the Cisco switches from the lab above.
All-AWS shop with no plans to change? CloudFormation is a fair choice. Anything multi-cloud or hybrid? Terraform.
Terraform vs Kubernetes
Different layers, so it’s rarely either-or. Kubernetes runs containers. Terraform can create the cluster Kubernetes runs on. Terraform vs Helm and Terraform vs Docker work out the same way: Docker builds and runs container images, Helm installs packaged apps into a Kubernetes cluster, and Terraform builds the infrastructure under both. A typical stack uses all three.
Ansible vs Puppet vs Chef
All three handle configuration management. The big difference is the agent. With Puppet, the primary server compiles a catalog for each node and a Puppet agent on that node applies it. Chef works the same way: Chef Infra Client is an agent on every node, pulling cookbooks from Chef Infra Server. Ansible pushes from one control node over SSH and installs no agent on the target.
For a learner, that settles Ansible vs Chef and Ansible vs Puppet. You can automate a lab switch with Ansible this afternoon. Puppet and Chef assume you can run their agent on every target, which fits server fleets you fully control. Chef vs Puppet is mostly a question of which one your employer already runs.
Where do Pulumi, OpenTofu and Ansible Tower fit?
- Pulumi does what Terraform does, but you write it in TypeScript, JavaScript, Python, Go, .NET, Java or YAML (it accepts HCL too). Good fit if you’re a developer first.
- OpenTofu is the fork of Terraform that started after HashiCorp’s licence switch. It’s MPL-2.0, run as a Linux Foundation project, and its latest release is 1.13.1. It reads state files from Terraform up to 1.5.x and works with Terraform providers through its own registry. Learn Terraform and you can read OpenTofu configs on day one.
- Ansible Tower is now called automation controller, part of Red Hat Ansible Automation Platform. It runs and governs playbooks centrally. So Ansible Tower vs Terraform compares a control plane for Ansible with a provisioning tool. They don’t compete.
Is Terraform still open source after IBM bought HashiCorp?
Not by the strict definition. Since version 1.6.0, released 2023-10-04, Terraform ships under the Business Source License, and the licence file now names IBM as the licensor. IBM completed its HashiCorp purchase on 2025-02-27. You can still use Terraform free in production. The licence’s extra grant allows that, unless you offer Terraform as a hosted or embedded product that competes with IBM’s paid versions.
Ansible stays GPL-3.0. Red Hat has been part of IBM since 2019-07-09, so one company now owns both tools.
For a learner, none of this changes the answer. If your employer moved to OpenTofu, your Terraform skills come with you.
Frequently asked questions
Can Ansible replace Terraform?
For small jobs, yes. Ansible has cloud modules, like amazon.aws.ec2_instance, that create and manage instances. What it can’t do is remember them. Delete a VLAN or a VM from a playbook and it stays put. Delete it from Terraform code and Terraform removes it. For anything you’ll create and tear down more than once, use Terraform.
Is Ansible easier to learn than Terraform?
For most beginners, yes. A playbook is YAML that reads top to bottom, and you can point it at a lab switch over SSH right away. Terraform asks you to learn HCL, providers and state before your first apply means much. Neither is hard. Terraform just has more concepts on day one.
Is Terraform or Ansible better for network automation?
Ansible, for most labs and existing networks. It speaks CLI over SSH, NETCONF and HTTP APIs, and it runs on the control node, so the device needs nothing extra. Terraform shines where a good vendor provider exists, like Cisco’s IOS XE provider, and you want the network managed with the same plan-and-apply workflow as your cloud.
Do I need Python to use Ansible?
On the control node, yes. Ansible is written in Python, and ansible-core 2.21 needs Python 3.12 or newer. On Windows, you’ll run the control node inside WSL. Linux targets need Python too, but network devices don’t. And you don’t need to write any Python to write playbooks.
Should I get Terraform Associate or the Red Hat Ansible certification first?
Terraform Associate is the quicker win: one hour, multiple choice, $70.50 USD. The Red Hat path needs the RHCSA plus the hands-on EX294. Network engineers have a third option that covers both tools: CCNA Automation (200-901), where Infrastructure and Automation is 20% of the exam.
Bottom line
- Terraform creates and destroys. Ansible configures. Terraform remembers, Ansible checks.
- Network engineer or Linux admin? Ansible first, then Terraform. Cloud engineer? The other way round.
- Run any Ansible state other than
mergedwith--checkbefore you run it for real.
Want to practise both on real labs? The DevOps Workbook covers Terraform and Ansible alongside Git, CI/CD, Docker and Kubernetes. On the network track, the CCNA Automation 200-901 workbook works through Python, APIs and Ansible against the exam blueprint. Just want the commands on one page? Grab the free Terraform commands cheat sheet and the free Ansible commands cheat sheet.