Terraform and Ansible are both infrastructure automation tools, but they solve different problems. Terraform provisions and manages cloud infrastructure: networks, instances, databases, IAM, and DNS, built from a declared end state and tracked in a state file. Ansible configures systems and deploys software, from installed packages to running services. It works through ordered tasks sent over SSH, WinRM, or an API, and keeps no state file.
That is why the question rarely ends with one winner. In most teams that run both, Terraform creates the VPC, the instances, and the database, and Ansible configures what runs on those instances. The useful questions are where the line between them sits and how to keep both under the same review rules.
Ansible vs Terraform at a Glance
- Purpose: Terraform provisions and changes infrastructure resources. Ansible configures operating systems and applications and runs operational tasks.
- Approach: Terraform is declarative: you describe the end state and it plans the steps. Ansible playbooks run tasks in order, and most modules are idempotent, so running a playbook twice leaves the same result.
- State: Terraform records every resource it manages in a state file. Ansible keeps no state; each run checks the target as it finds it.
- Language: Terraform uses HCL. Ansible uses YAML playbooks with Jinja2 templating (
{{ variable }}placeholders).
- Connection: Terraform calls provider APIs. Ansible connects to Linux hosts over SSH and Windows hosts over WinRM (Windows Remote Management), or calls cloud APIs from the machine where you run
ansible-playbook. Neither needs an agent on the target.
- Previewing changes: Terraform shows a plan before applying. Ansible has check mode (
--check), often paired with--diff, to report what a run would change.
- Removal: When you remove a resource from code, Terraform destroys it on the next apply. Ansible removes things only when a task says so, for example with
state: absent.
- Licensing: Terraform has been under the Business Source License since 2023, and OpenTofu is its open-source fork under MPL 2.0. Ansible is open source under GPLv3, and Red Hat sells Ansible Automation Platform on top of it.
State: Why Terraform Knows What It Built
Terraform's state file maps every resource in your code to a real object in the cloud. That mapping is what lets Terraform show an exact plan, rename or delete resources cleanly, and notice drift: when someone changes a security group in the console, the next refreshed plan shows the difference.
Ansible works without that memory. A playbook describes tasks, not a full inventory of everything it ever created. That keeps Ansible simple and flexible, but it also means Ansible cannot tell you which cloud resources it is responsible for, and deleting something requires an explicit task. For servers and applications that is usually fine. For cloud resources with long lifecycles, it is the main reason teams reach for Terraform.
Procedural Tasks vs Declared End State
An Ansible playbook runs top to bottom: install the package, write the config file, restart the service if the file changed. Order matters, and that is often what you want when configuring a machine. Roles and handlers make playbooks reusable across many hosts.
Terraform works out order itself from the dependencies between resources. You declare that a subnet belongs to a VPC and an instance sits in that subnet, and Terraform creates them in the right sequence, in parallel where it can. You do not write steps; you write the result.
Where Each Tool Falls Short
Terraform is a poor fit for configuring what runs inside a machine. It has provisioners that can run scripts on a new instance, but HashiCorp's own documentation describes them as a last resort, because Terraform cannot model or plan what a script does. Long-running package installs and service configuration belong in a configuration tool or a prebuilt image.
Ansible can create cloud resources too. Its modules ship in collections, installable packages grouped by platform: the amazon.aws collection includes amazon.aws.ec2_instance, amazon.aws.s3_bucket, and amazon.aws.ec2_vpc_net, so a playbook can create instances, buckets, and VPCs. For small or short-lived setups that works. At scale, the lack of state shows: renaming a resource, removing one, or answering "what did we create in this account" becomes a scripting problem instead of a plan.
Using Ansible and Terraform Together
Three patterns are common.
- Terraform provisions, Ansible configures. Terraform creates instances and tags them. Ansible builds its inventory from the cloud using the
amazon.aws.aws_ec2inventory plugin, which builds the host list from EC2 tags each time the playbook runs instead of from a static hosts file, or through the Terraform provider Ansible publishes (ansible/ansible), then configures the hosts.
- Ansible drives Terraform. The
cloud.terraformcollection lets a playbook run Terraform and read its outputs, which suits teams whose operations already run through Ansible.
- Images instead of configuration. Ansible runs once, at image build time, to build a machine image such as an AMI with Packer. Terraform deploys instances from that image, and nothing is configured on live servers.
Whichever pattern you use, keep the order explicit in your pipeline: approve and apply the infrastructure change first, then run configuration in check mode and review the result before the real run.
Which Should You Choose?
Choose Terraform or OpenTofu for cloud resources with a lifecycle: networks, clusters, databases, IAM, and anything you need to change, rename, or delete cleanly later.
Choose Ansible for what runs on servers and network devices: packages, configuration files, services, users, patching, and one-off operational tasks across many hosts.
Choose both when you run long-lived servers. Most teams with virtual machines end up here, and the gap to manage is not the tools themselves but the handoff: who approved the infrastructure change, who approved the configuration run, and whether they were reviewed with the same rules.
Running Both Under One Review Process
ops0 runs Terraform and OpenTofu projects with plan review, policy checks for CIS, SOC 2, HIPAA, ISO 27001, ISO 27002, and GDPR, and an approval step where the person who starts a deployment cannot approve it. See IaC in ops0.
On the configuration side, ops0 generates Ansible playbooks and inventories with server and group context, runs a dry run first, and sends the run through approval before it executes against your hosts. See Configurations. Both sides read from the same read-only discovery of your clouds, so the servers a playbook targets are the same ones you can see in your inventory.
Can Ansible replace Terraform?
For small or short-lived setups, sometimes. Ansible's amazon.aws collection, its official package of AWS modules, can create EC2 instances, S3 buckets, and VPCs from a playbook. What it lacks is a state file: Ansible does not remember what it created, so renaming or deleting a resource means writing another task. Most teams use Terraform for cloud resources with a long lifecycle.
Can Terraform replace Ansible?
Not well. Terraform can run scripts on new instances through provisioners, but HashiCorp describes them as a last resort because Terraform cannot plan what a script does. Configuring packages and services inside machines is what Ansible is built for.
Should I use Ansible and Terraform together?
If you run long-lived servers, usually yes. Terraform creates the infrastructure and Ansible configures the hosts, using a dynamic inventory or the ansible/ansible Terraform provider to find them. Keep the order explicit in your pipeline and review both runs.
Is Ansible declarative or procedural?
Both. Individual Ansible modules are declarative and idempotent: you state that a package should be present and the module checks before acting. Playbooks are procedural: tasks run in the order you write them.
Does Ansible have a state file like Terraform?
No. Ansible checks each target as it finds it on every run. That keeps it simple, but it means Ansible cannot list everything it created or remove resources unless a task explicitly does so.
- Ansible vs. Terraform: Red Hat. Provisioning versus configuration from Ansible's maintainer.
- Provisioners: HashiCorp. Why provisioners are a last resort.
- State: HashiCorp. Purpose of Terraform state, backends, and locking.
- Ansible provider: Terraform Registry. Adding Terraform-created hosts to Ansible inventory.
- cloud.terraform collection: Ansible Galaxy. Running Terraform from Ansible playbooks.
- Validating tasks: check mode and diff mode: Ansible. Previewing playbook changes.