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

  1. Terraform provisions the cloud infrastructure: resource groups, virtual networks, VMs, managed databases, DNS records, firewall rules.
  2. 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

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.