Cloud Tech by Victor
DevOpsTerraformAnsible

Terraform vs Ansible

Terraform provisions infrastructure and Ansible configures it. How the two tools differ in model, state, and strengths, and how they pair.

Updated 2026-07-243 min read

Overview

Terraform and Ansible get shelved together as "infrastructure as code," which hides the fact that they were built for different layers of the problem. Terraform is a provisioning tool: it creates, changes, and destroys infrastructure, networks, VMs, databases, DNS, by declaring a desired end state and diffing it against a state file that records what it built. Ansible is a configuration management and automation tool: it connects to machines that already exist (over SSH or WinRM, agentless) and runs ordered, idempotent tasks, install packages, template config files, restart services, orchestrate a rolling deploy.

The overlap that causes the confusion is real, Ansible has cloud modules that can create a VM, and Terraform has provisioners that can run scripts on one, but each is weakest exactly where the other is strongest.

Feature comparison

TerraformAnsible
Primary jobProvisioning infrastructureConfiguring machines and orchestrating tasks
ModelDeclarative; describe end state, tool computes the diffTask-based; ordered plays of idempotent modules
LanguageHCLYAML playbooks (plus Jinja2 templating)
StateExplicit state file; drift is detectable via planNo central state; each run re-checks reality per task
Dry runterraform plan, exact preview of every change--check mode, best-effort per module
Dependency handlingAutomatic resource graphYou order tasks yourself (handlers, notify, roles)
Agents / accessNone; talks to provider APIs with credentialsNone; SSH/WinRM to targets
Deleting thingsFirst-class; removing config destroys the resourceWeak; absent tasks change nothing, deletion is explicit
EcosystemProvider registry (thousands of APIs)Collections via Ansible Galaxy, huge module library
LicenseBusiness Source License 1.1 (open-source fork: OpenTofu)GPLv3 (ansible-core), backed by Red Hat
Typical triggerInfrastructure change in version controlProvisioning hand-off, app deploys, ad-hoc ops, patching

Where Terraform tends to win

The lifecycle of infrastructure itself. Because Terraform tracks what it created, it can show you an exact plan of what will change, detect drift between code and reality, and, critically, destroy what you remove from the code. Its dependency graph orders creation across dozens of interrelated resources (VPC before subnet before VM) without you scripting the sequence. For standing up environments repeatably, dev/staging/prod from the same modules, a declarative tool with state is the right shape, and Ansible's create-a-VM modules give you none of that lifecycle tracking.

Where Ansible tends to win

Everything that happens on and across running machines. Configuring an OS, rolling out an application version across a fleet with health checks between batches, patching, and one-off operational tasks ("restart nginx on every web node in rack 3") are procedural jobs, and Ansible's ordered plays, inventory groups, and thousands of modules are built for exactly that. Being agentless matters here: anything reachable over SSH, bare metal, network switches, legacy VMs no cloud API knows about, is automatable with nothing installed on the target.

Note

The strongest pattern is not choosing between them: Terraform provisions the infrastructure and hands off, via inventory generated from its outputs or a dynamic inventory plugin, to Ansible, which configures what Terraform built. On cloud-native stacks, immutable images (Packer) or user-data/cloud-init can shrink Ansible's role, but the division of labor, lifecycle vs configuration, stays the same.

Verdict

Ask what you're automating. If the answer is the existence of infrastructure, creating it, changing it, tearing it down, in sync with version-controlled code, that's Terraform. If the answer is the behavior of machines, packages, config files, services, deploy sequences, that's Ansible. Teams that force one tool to do both jobs end up either shell-scripting configuration through Terraform provisioners or losing lifecycle tracking by provisioning through Ansible; using each at its own layer is simpler than either workaround.

References

ShareXLinkedInReddit
Was this page helpful?
Suggest an improvement