“Terraform or Ansible?” comes up often as a choice to make, when the two tools actually answer different questions: Terraform decides which resources exist, Ansible decides how what exists gets configured. The confusion comes from a real but partial overlap, not genuine competition.
What each one describes
Terraform, a declarative infrastructure as code tool, describes a target state of resources (servers, networks, managed databases) and computes the operations to reach it from the current state. Ansible describes steps to run on machines that already exist: install a package, copy a configuration file, restart a service. The difference isn’t one of degree, it’s one of nature: Terraform answers “what should exist,” Ansible answers “how should what exists be configured.”
# Terraform: the machine should exist, with this type
# and this image, nothing more
resource "aws_instance" "web" {
ami = "ami-12345"
instance_type = "t3.medium"
}
# Ansible: once the machine is there, these packages
# and this configuration should be applied
- name: Install nginx
apt:
name: nginx
state: present
The overlap that fuels the confusion
Both tools can technically provision a cloud machine (Ansible has cloud modules), and Terraform can technically run configuration scripts via provisioner "remote-exec". That functional overlap keeps alive the illusion of a real choice to make, when using either outside its natural domain is generally discouraged by both tools’ own documentation: Terraform’s provisioners are documented as a last resort, not a pattern to reach for by default.
# Technically possible, discouraged by Terraform
# itself: it's not its job
provisioner "remote-exec" {
inline = ["apt-get install -y nginx"]
}
The pattern that chains them, the most common in practice
The most widespread usage doesn’t choose between the two, it chains them: Terraform provisions the machines and outputs their IP addresses, Ansible consumes that output as a dynamic inventory to configure the freshly created machines. Each tool stays on its natural ground; the boundary between them is the exact moment the machine exists but isn’t configured yet.
# Terraform's output becomes Ansible's inventory,
# the boundary between "provisioning" and "configuring"
terraform output -json instance_ips > inventory.json
ansible-playbook -i inventory.json site.yml
Where Kubernetes changes the question
On a Kubernetes cluster, the question plays out differently: Terraform provisions the cluster itself (nodes, network), but configuring what runs on top of it generally goes through Kubernetes manifests or Helm charts, not Ansible. Ansible keeps its relevance for whatever stays outside the cluster: system configuration of the nodes themselves, bootstrapping before a node joins the cluster, or managing a hybrid infrastructure mixing classic VMs and Kubernetes.
Takeaway
Terraform and Ansible aren’t competitors despite the frequent question: Terraform decides which resources exist, Ansible decides how what exists gets configured, a distinction of nature, not degree. The functional overlap exists but stays marginal and is discouraged by both tools themselves outside their natural domain. The most common pattern chains them rather than choosing: Terraform provisions, its output feeds Ansible’s inventory which configures, a clean boundary that structures most CI/CD industrialization pipelines still managing infrastructure outside Kubernetes.