COMPARISON

Ansible vs Terraform — When to Use Which (With a Real Production Example)

By Akshay Ghalme·April 12, 2026·10 min read

Ansible and Terraform are not competitors — they solve different problems. Terraform provisions the cloud infrastructure (EC2 instances, VPCs, RDS databases, load balancers). Ansible configures the software that runs inside that infrastructure (NGINX, application runtimes, system packages, users). In production, you use both: Terraform builds the building, Ansible furnishes the rooms.

This confusion comes up constantly in interviews and on DevOps forums. Someone asks "should I learn Ansible or Terraform?" as if they need to pick one. The answer is that serious DevOps engineers use both, and knowing where the line is between them is what separates a junior from someone who has actually run production infrastructure.

I have used both for years managing multi-tenant SaaS infrastructure on AWS. Here is how they actually fit together, with real code you can copy.

The Core Difference in One Sentence

Terraform is an Infrastructure-as-Code provisioning tool. It creates, modifies, and destroys cloud resources through provider APIs. Ansible is a configuration management tool. It connects to already-running machines over SSH and configures software on them.

Terraform's question: "Does this cloud resource exist with the right settings?" Ansible's question: "Is the software on this machine in the right state?"

Quick Comparison Table

DimensionTerraformAnsible
Primary jobProvision cloud infrastructureConfigure software on running machines
LanguageHCL (declarative)YAML playbooks (procedural/declarative mix)
State modelStateful (state file tracks resources)Stateless (idempotent tasks, no persistent state)
Execution modelDeclarative: desired state → plan → applyPush-based: connects over SSH and runs tasks
TransportCloud provider APIs (AWS, GCP, Azure)SSH for Linux, WinRM for Windows
Agent requiredNoneNone (agentless)
Best forVPCs, EC2, RDS, load balancers, DNSPackage installs, config files, services, users
Not good atOngoing OS/software configurationManaging cloud infrastructure at scale

A Real Production Example

Let me show you exactly how this works with a real scenario: you need to deploy three EC2 web servers behind an Application Load Balancer, each running NGINX as a reverse proxy to a Node.js application.

Step 1 — Terraform provisions the infrastructure

Terraform creates the VPC, subnets, security groups, EC2 instances, and ALB. It does not install NGINX or configure the application.

# main.tf
resource "aws_instance" "web" {
  count         = 3
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.medium"
  subnet_id     = aws_subnet.private[count.index].id

  vpc_security_group_ids = [aws_security_group.web.id]
  key_name               = aws_key_pair.deploy.key_name

  tags = {
    Name = "web-${count.index + 1}"
    Role = "webserver"
    Env  = "production"
  }
}

output "web_ips" {
  value = aws_instance.web[*].private_ip
}

After terraform apply, you have three running EC2 instances with nothing on them except the base Amazon Linux AMI. No NGINX. No Node.js. No application code. Terraform's job is done.

Step 2 — Ansible configures the software inside

Now Ansible takes over. It reads the running EC2 instances from an AWS dynamic inventory (filtered by the Role=webserver tag Terraform set), connects over SSH, and configures them.

# inventory/aws_ec2.yaml
plugin: amazon.aws.aws_ec2
regions:
  - us-east-1
filters:
  tag:Role: webserver
  tag:Env: production
  instance-state-name: running
keyed_groups:
  - key: tags.Role
    prefix: role
# playbooks/webserver.yml
- name: Configure web servers
  hosts: role_webserver
  become: yes
  tasks:
    - name: Install NGINX
      ansible.builtin.package:
        name: nginx
        state: present

    - name: Deploy NGINX config
      ansible.builtin.template:
        src: templates/nginx.conf.j2
        dest: /etc/nginx/nginx.conf
        mode: '0644'
      notify: restart nginx

    - name: Install Node.js 20
      ansible.builtin.shell: |
        curl -fsSL https://rpm.nodesource.com/setup_20.x | bash -
        yum install -y nodejs
      args:
        creates: /usr/bin/node

    - name: Ensure NGINX is running
      ansible.builtin.service:
        name: nginx
        state: started
        enabled: yes

  handlers:
    - name: restart nginx
      ansible.builtin.service:
        name: nginx
        state: restarted

Run it: ansible-playbook -i inventory/aws_ec2.yaml playbooks/webserver.yml. Ansible SSHs into all three instances in parallel, installs packages, drops config files, and restarts services. If you run it again, nothing changes — because every task is idempotent.

Why this separation matters

If you tried to do the NGINX install with Terraform's user_data or remote-exec, you would hit a wall the first time you needed to update NGINX config on existing servers. Terraform would either do nothing (user_data only runs on first boot) or force-replace the instance (destroying it and creating a new one). Ansible can push a config change to running servers in seconds without touching the infrastructure.

Free Download

Terraform & Kubernetes — 100 Senior Interview Questions (PDF)

133 pages. Every question has a direct answer, mental model, and production-level depth. The way 5-year engineers actually think about Terraform, Kubernetes, and Ansible.

Download PDF

When to Use Terraform

Reach for Terraform when you need to:

  • Create or destroy cloud resources (EC2, RDS, S3, IAM, Route 53, ALB)
  • Manage a production VPC with subnets, route tables, and NAT gateways
  • Provision managed services like EKS, ECS, Lambda, or DynamoDB
  • Track infrastructure as code with a state file and dependency graph
  • Enforce desired state across multiple environments (dev, staging, prod)
  • Build reusable infrastructure modules your team can share

Terraform shines when the question is "does this cloud resource exist?" It has a state file, a plan/apply workflow, and a massive provider ecosystem covering AWS, GCP, Azure, Cloudflare, GitHub, Datadog, and 3000+ other services.

When to Use Ansible

Reach for Ansible when you need to:

  • Install and configure software on running machines (NGINX, PostgreSQL, application runtimes)
  • Push configuration file updates to a fleet of servers
  • Manage users, SSH keys, sudoers, and file permissions
  • Run ad-hoc commands across hundreds of servers in parallel
  • Apply OS patches and security updates on a schedule
  • Bootstrap bastion hosts, CI runners, or non-containerized workloads
  • Orchestrate multi-step deployments with rolling updates and health checks

Ansible shines when the question is "is this software in the right state on this machine?" It is agentless, idempotent, and can target thousands of hosts over SSH without installing anything on them.

What Happens If You Try to Use Only One

Terraform-only (no Ansible)

You can get pretty far with just Terraform if you use user_data scripts, AMI baking with Packer, or container orchestration. For stateless containerized workloads on ECS or EKS, you genuinely may never need Ansible.

But the moment you need to update configuration on running servers without replacing them, Terraform becomes painful. You end up writing brittle remote-exec provisioners or rebuilding AMIs for every config change. That is a 30-minute job in Ansible.

Ansible-only (no Terraform)

Ansible has cloud modules like amazon.aws.ec2_instance that can create EC2 resources directly. Technically, you can provision AWS infrastructure with Ansible alone.

But Ansible has no state file, no dependency graph, and no plan phase. It does not know what exists unless you query it every run. At scale, this becomes fragile — infrastructure drift appears, deletions are risky, and there is no way to see what will change before it happens. This is exactly the problem Terraform was built to solve.

The Hybrid Approach in Production

In every real production environment I have worked in, the pattern is the same:

  1. Terraform provisions the cloud layer — VPCs, subnets, EC2, RDS, IAM, ALBs, DNS, monitoring. State lives in S3 with DynamoDB locking.
  2. Ansible handles the machine layer — installs packages, drops config files, manages services, runs deployments on the instances Terraform created.
  3. Terraform outputs feed Ansible inventory — either through dynamic inventory plugins (aws_ec2) or by exporting Terraform outputs to a file Ansible reads.
  4. CI/CD runs them in sequenceterraform apply first, then ansible-playbook on the resources Terraform created.

This separation keeps each tool doing what it is best at and prevents the nightmare of trying to do configuration management inside a provisioning tool, or infrastructure provisioning inside a configuration manager.

What About Containers?

If your entire workload runs in containers on ECS or EKS, Ansible's role shrinks dramatically. The container image is your configuration — built with Dockerfile, not Ansible. Terraform provisions the cluster, and Kubernetes manifests or ECS task definitions handle the rest.

But even in container-heavy shops, Ansible still shows up for:

  • Bastion hosts and jump servers
  • CI/CD runners (GitHub Actions self-hosted, Jenkins agents)
  • Database servers running on EC2 for latency or compliance reasons
  • Legacy VM workloads that have not been containerized yet
  • Network appliances, firewalls, and on-prem devices

Ansible is not going anywhere — it is just working in a smaller slice of the stack.

My Recommendation

Learn Terraform first. It is the foundation of modern cloud infrastructure and has the larger job market. Get comfortable with HCL, state management, modules, and the plan/apply workflow.

Then learn Ansible — not as a competitor to Terraform, but as the tool that takes over once Terraform hands you a running machine. The two together let you manage everything from the VPC down to the config file of an individual service.

Anyone who tells you to pick one has not run production infrastructure at scale.

Frequently Asked Questions

Should I use Ansible or Terraform?

Use both. Terraform provisions cloud infrastructure (EC2, VPC, RDS). Ansible configures software inside those machines (NGINX, Node.js, system packages). They are complementary tools, not alternatives.

Can Ansible replace Terraform?

Not cleanly. Ansible can create cloud resources via cloud modules, but it lacks a state file, dependency graph, and plan/apply workflow. At scale this leads to drift and fragile automation. Terraform is purpose-built for provisioning.

Can Terraform replace Ansible?

Not for configuration management. Terraform has user_data and remote-exec, but they are one-shot and not idempotent. Ongoing software configuration needs Ansible or a similar tool.

Do I still need Ansible if I use containers?

Less than before, but often yes. Even container-first teams use Ansible for bastion hosts, CI runners, database VMs, and legacy workloads. Only fully containerized greenfield projects can skip it.

Is Ansible stateful like Terraform?

No. Ansible is stateless — it runs idempotent tasks over SSH and leaves nothing persistent on the target. Terraform is stateful — it stores resource state in a state file and computes a diff on every run.


Next Steps

If you want to go deeper on either tool, these guides are the fastest path:

  1. Set up Terraform remote state with S3 + DynamoDB — the foundation every Terraform project needs
  2. Build a production VPC with Terraform — your first real infrastructure project
  3. Terraform vs CloudFormation — if you are still deciding between IaC tools
  4. Free DevOps resources — including the Terraform/Kubernetes/Ansible 100Q interview guide

Each guide includes real code you can deploy, plus open-source Terraform modules for when you want to skip the manual work.

AG

Akshay Ghalme

AWS DevOps Engineer with 3+ years building production cloud infrastructure. AWS Certified Solutions Architect. Currently managing a multi-tenant SaaS platform serving 1000+ customers.

More Guides & Terraform Modules

Every guide comes with a matching open-source Terraform module you can deploy right away.