Back to Linux guides

Ansible vs Terraform: A Comprehensive Comparison

Ayooluwa Isaiah
Updated on March 24, 2025

Infrastructure as Code (IaC) has revolutionized how we deploy and manage IT infrastructure. Instead of manually configuring servers and services or using custom scripts, IaC allows teams to define infrastructure requirements in code, making deployments reproducible, consistent, and version-controlled. At the forefront of this revolution are Ansible and Terraform, two powerful tools that have become fundamental to modern DevOps practices.

Ansible emerged as a simple yet powerful automation tool for configuration management and application deployment. It uses a procedural approach with human-readable YAML syntax to define the desired state of systems. Terraform, on the other hand, was built specifically for infrastructure provisioning using a declarative approach, focusing on maintaining state across multiple cloud providers.

This article aims to help you understand both technologies, their differences, use cases, and how they can complement each other in a modern infrastructure pipeline. We'll explore their architectures, benefits, limitations, and practical scenarios where they shine individually or work together.

Understanding Ansible

Ansible is an open-source automation platform that enables infrastructure as code, application deployment, configuration management, and task automation. It follows a push-based model where a control node executes tasks on managed nodes without requiring any agents to be installed on those systems.

Unlike some other configuration management tools, Ansible uses SSH for communication with remote systems, making it agentless and lightweight. This design allows Ansible to automate both legacy and modern infrastructure without adding overhead to managed systems.

Ansible sits at the intersection of configuration management and orchestration:

  • Configuration management: Ansible ensures systems are in a desired state by installing packages, configuring services, and managing files

  • Orchestration: Ansible can coordinate complex multi-step processes across multiple systems, such as application deployments or infrastructure updates

Key Ansible components

1. Playbooks

Playbooks are Ansible's configuration, deployment, and orchestration language. They describe a policy you want your remote systems to enforce or a set of steps in a general IT process. Playbooks are written in YAML format, making them easy to read and write.

Here's an example of a simple playbook that installs and starts the Nginx web server:

playbook.yml
---
- name: Install and configure nginx
 hosts: webservers
 become: yes
 tasks:
   - name: Install nginx package
     apt:
       name: nginx
       state: present
       update_cache: yes

   - name: Start nginx service
     service:
       name: nginx
       state: started
       enabled: yes

   - name: Create custom index.html
     copy:
       content: "<html><body><h1>Hello from Ansible!</h1></body></html>"
       dest: /var/www/html/index.html

To run this playbook:

 
ansible-playbook playbook.yml

This command will execute the playbook against all hosts in the "webservers" group defined in your inventory.

2. Roles

Roles in Ansible provide a way to organize playbooks and all related files (such as variables, handlers, and tasks) to make them more reusable and modular. Roles have a specific directory structure:

 
role_name/
 defaults/    # Default variables
 files/       # Files to be deployed
 handlers/    # Handlers to be triggered
 meta/        # Metadata for the role
 tasks/       # Tasks to be executed
 templates/   # Templates to be deployed
 vars/        # Role variables

You can reference and use roles in a playbook like this:

roles_playbook.yml
---
- hosts: webservers
 roles:
   - nginx
   - app_server

3. Modules

Modules are the units of work in Ansible. Each module is designed to handle a specific task, such as managing packages, users, files, or services. Ansible comes with over 3,000 built-in modules, and you can also write custom modules if needed.

Common modules include:

  • apt/yum: For package management
  • service: For managing services
  • copy/template: For file management
  • user: For user management
  • command/shell: For executing commands or scripts

Example of using modules in an ad-hoc command:

 
ansible webservers -m apt -a "name=nginx state=present" -b

This command uses the apt module to ensure Nginx is installed on all servers in the "webservers" group.

4. Inventory files

Inventory files define the hosts and groups of hosts upon which commands, modules, and tasks in a playbook operate. The default inventory file is located at /etc/ansible/hosts, but you can specify a different inventory file at the command line.

Here's an example inventory file:

inventory.ini
[webservers]
web1.example.com
web2.example.com

[dbservers]
db1.example.com
db2.example.com

[dc:children]
webservers
dbservers

[dc:vars]
ansible_user=devops

This inventory defines two groups (webservers and dbservers), a group that includes both groups (dc), and sets variables that apply to the dc group.

Benefits of Ansible

  • Agentless architecture: Ansible only requires SSH and Python on the managed nodes, eliminating the need to install and maintain agents. This makes it particularly suitable for environments where installing additional software is challenging or prohibited.

  • Human-readable YAML syntax: Playbooks are written in YAML, which is easy to learn and understand, even for those without extensive programming experience. This low barrier to entry makes Ansible accessible to a wide range of IT professionals.

  • Extensive module library: With thousands of built-in modules, Ansible can automate virtually any IT task, from managing cloud resources to configuring network devices.

  • Idempotency: Ansible modules are designed to be idempotent, meaning they can be run multiple times without changing the result beyond the initial application. If a system is already in the desired state, Ansible won't make unnecessary changes.

Limitations of Ansible

  • Primarily procedural approach: Ansible follows a primarily procedural approach, executing tasks in sequence. This can make complex state management more challenging compared to declarative tools.

  • Limited state management: Ansible doesn't maintain a state file of managed resources (unlike Terraform). It determines the current state by directly querying systems, which can sometimes lead to drift if changes are made outside of Ansible.

  • Performance with large infrastructures: As Ansible executes tasks sequentially by default, managing large numbers of hosts can become time-consuming without using strategies like parallelization.

Understanding Terraform

Terraform is an open-source infrastructure as code tool created by HashiCorp. It allows users to define and provision infrastructure resources using a declarative configuration language called HashiCorp Configuration Language (HCL). Terraform can manage resources across various cloud providers (AWS, Azure, GCP) and services (Kubernetes, GitHub, Fastly) through a plugin architecture with providers.

Unlike Ansible, which focuses on configuration management, Terraform specializes in infrastructure provisioning—creating, modifying, and destroying infrastructure resources like virtual machines, networks, and storage.

Terraform architecture

Terraform's architecture consists of several key components:

  • Core: The Terraform core reads configuration files, builds the resource graph, and executes plans to reach the desired state.

  • Providers: Plugins that implement resource types for specific platforms or services. Examples include the AWS provider, Azure provider, and Google Cloud provider.

providers.tf
terraform {
 required_providers {
   aws = {
     source  = "hashicorp/aws"
     version = "~> 4.0"
   }
 }
}

provider "aws" {
 region = "us-west-2"
}
  • State files: Terraform stores the state of the managed infrastructure in a state file. This state file maps real-world resources to your configuration, keeps track of metadata, and improves performance for large infrastructures.

  • Resource graph: Terraform builds a dependency graph of resources based on your configuration, allowing it to determine the correct order for creating, updating, or destroying resources.

Key Terraform concepts

1. Resources and data sources

Resources are infrastructure objects that Terraform manages, such as virtual machines, DNS records, or cloud storage buckets. Data sources allow Terraform to use information defined outside of Terraform, imported from existing infrastructure or other sources.

ec2_instance.tf
resource "aws_instance" "web_server" {
 ami           = "ami-0c55b159cbfafe1f0"
 instance_type = "t2.micro"

 tags = {
   Name = "WebServer"
   Environment = "Production"
 }
}

data "aws_vpc" "existing_vpc" {
 default = true
}

2. Variables and outputs

Variables allow parameterizing your configurations, making them more reusable. Outputs provide a way to extract information about your infrastructure that can be used elsewhere or displayed to users.

variables.tf
variable "instance_type" {
 description = "EC2 instance type"
 default     = "t2.micro"
 type        = string
}

variable "environment" {
 description = "Deployment environment"
 type        = string
}
outputs.tf
output "web_server_public_ip" {
 description = "Public IP address of the web server"
 value       = aws_instance.web_server.public_ip
}

3. Modules

Modules are containers for multiple resources that are used together. They allow you to create reusable components and promote code organization.

main.tf
module "vpc" {
 source = "./modules/vpc"

 cidr_block = "10.0.0.0/16"
 environment = var.environment
}

module "web_servers" {
 source = "./modules/web_servers"

 vpc_id = module.vpc.vpc_id
 instance_type = var.instance_type
 environment = var.environment
}

4. Terraform workflow

Terraform follows a core workflow with these main commands:

 
# Initialize working directory, install providers
terraform init

# Preview changes Terraform will make
terraform plan

# Apply the changes to reach desired state
terraform apply

# Destroy all managed resources
terraform destroy

This workflow provides a clear process for managing infrastructure changes, with explicit steps for validation before applying changes.

Benefits of Terraform

  • Declarative approach: Terraform uses a declarative language where you specify the desired end state rather than the steps to get there. Terraform figures out how to achieve that state.

  • State management: Terraform's state file tracks all managed resources, enabling it to detect drift and understand relationships between resources, even across different providers.

 
terraform plan # Check for infrastructure drift

If someone manually changes a resource, this command will show the differences between the actual state and the desired state.

Provider ecosystem: With hundreds of providers covering major cloud platforms, services, and systems, Terraform can manage nearly any infrastructure resource.

Plan and apply workflow: The separation between planning changes and applying them gives teams the opportunity to review and approve changes before implementation, improving safety and collaboration.

Challenges with Terraform

  • Learning curve for HCL: HashiCorp Configuration Language can be challenging for beginners, especially when dealing with complex expressions and functions.

  • State management complexity: The state file is critical to Terraform's operation but can become a point of contention in team environments. Remote state storage and locking mechanisms help address this but add complexity.

  • Limited configuration management capabilities: While Terraform excels at provisioning infrastructure, it has limited capabilities for configuring the operating system and applications running on that infrastructure.

How Ansible and Terraform work together

The complementary relationship

Terraform and Ansible have complementary strengths and can work together effectively in a modern infrastructure pipeline:

  • Terraform excels at provisioning the underlying infrastructure: VMs, networks, load balancers, and other cloud resources
  • Ansible excels at configuring that infrastructure: installing packages, configuring services, deploying applications

This division of responsibilities creates a clear separation of concerns in your IaC implementation:

  1. Use Terraform to create the infrastructure resources
  2. Use Ansible to configure those resources and deploy applications

![Diagram showing Terraform and Ansible workflow]

Integration strategies

There are several ways to integrate Terraform and Ansible:

Using Terraform outputs with Ansible

Terraform can output information about provisioned resources (like IP addresses), which Ansible can use to target those resources.

outputs.tf
output "web_server_ips" {
 value = aws_instance.web_servers[*].public_ip
}

You can then generate an Ansible inventory from these outputs:

create_inventory.sh
#!/bin/bash
terraform output -json web_server_ips | jq -r '.[]' > web_servers.txt

echo "[web]" > inventory.ini
cat web_servers.txt | while read ip; do
 echo "$ip ansible_user=ubuntu" >> inventory.ini
done

Ansible as a Terraform provisioner

Terraform can use provisioners to execute scripts or commands on resources after they're created. You can use the local-exec provisioner to run Ansible against newly created resources:

main.tf
resource "aws_instance" "web_server" {
 ami           = "ami-0c55b159cbfafe1f0"
 instance_type = "t2.micro"

 provisioner "local-exec" {
   command = "ansible-playbook -i '${self.public_ip},' playbook.yml"
 }
}

Separate but coordinated workflows

In more complex environments, you might maintain separate Terraform and Ansible codebases but coordinate their execution through a CI/CD pipeline:

  1. Terraform creates/updates infrastructure
  2. Terraform outputs are processed to create Ansible inventory
  3. Ansible runs to configure the infrastructure
  4. Tests verify the environment is properly set up

Practical workflow example

Let's look at a practical example of using Terraform and Ansible together:

Define infrastructure with Terraform

main.tf
provider "aws" {
 region = "us-west-2"
}

resource "aws_instance" "app_servers" {
 count         = 2
 ami           = "ami-0c55b159cbfafe1f0"
 instance_type = "t2.micro"
 key_name      = "deployment_key"

 tags = {
   Name = "app-server-${count.index}"
   Role = "application"
 }
}

output "app_server_ips" {
 value = aws_instance.app_servers[*].public_ip
}

Create dynamic inventory for Ansible

dynamic_inventory.py
#!/usr/bin/env python3
import json
import subprocess

# Get Terraform outputs
result = subprocess.run(['terraform', 'output', '-json'], capture_output=True, text=True)
tf_outputs = json.loads(result.stdout)

# Create Ansible inventory
inventory = {
   'app': {
       'hosts': {}
   },
   '_meta': {
       'hostvars': {}
   }
}

for i, ip in enumerate(tf_outputs['app_server_ips']['value']):
   host_name = f"app-server-{i}"
   inventory['app']['hosts'][host_name] = {}
   inventory['_meta']['hostvars'][host_name] = {
       'ansible_host': ip,
       'ansible_user': 'ubuntu'
   }

print(json.dumps(inventory))

Configure servers with Ansible

app_setup.yml
---
- name: Configure application servers
 hosts: app
 become: yes
 tasks:
   - name: Update apt cache
     apt:
       update_cache: yes

   - name: Install required packages
     apt:
       name:
         - nginx
         - python3
         - python3-pip
         - nodejs
         - npm
       state: present

   - name: Configure Nginx
     template:
       src: nginx.conf.j2
       dest: /etc/nginx/sites-available/default
     notify: Reload Nginx

   - name: Deploy application
     git:
       repo: https://github.com/example/app.git
       dest: /var/www/app

   - name: Install application dependencies
     npm:
       path: /var/www/app
       state: present

   - name: Start application service
     systemd:
       name: app
       enabled: yes
       state: started

 handlers:
   - name: Reload Nginx
     service:
       name: nginx
       state: reloaded

Execute the workflow

 
# Initialize Terraform
terraform init

# Create infrastructure
terraform apply -auto-approve

# Configure servers with Ansible
ansible-playbook -i dynamic_inventory.py app_setup.yml

This workflow demonstrates how Terraform and Ansible can work together to provide a complete solution: Terraform handles the infrastructure provisioning, while Ansible manages the configuration and application deployment.

When to use Ansible or Terraform

Use cases for Ansible alone

Ansible is often sufficient by itself in several scenarios:

  • Configuration management of existing infrastructure: When you already have infrastructure in place and need to maintain consistent configurations across servers, Ansible excels at ensuring systems are in the desired state.

  • Application deployment: Ansible's playbooks provide a straightforward way to automate application deployments, including copying files, setting up services, and performing necessary pre and post-deployment tasks.

  • Ad-hoc commands and operations: Ansible's command-line interface makes it simple to run one-off commands across multiple servers, which is useful for maintenance tasks or troubleshooting.

 
# Restart a service on all web servers
ansible webservers -m service -a "name=nginx state=restarted" -b

# Check disk space on all servers
ansible all -m shell -a "df -h"
  • Legacy infrastructure management: For environments with legacy systems that may not be easily managed through cloud APIs, Ansible's agentless approach provides a way to automate management without installing additional software.

Use cases for Terraform

Terraform is the better choice in these scenarios:

  • Cloud infrastructure provisioning: When creating resources across cloud providers, Terraform's provider ecosystem and declarative approach make it easy to define and manage complex infrastructure.

  • Multi-cloud deployments: When working across multiple cloud providers, Terraform provides a consistent workflow and language for managing resources, regardless of the provider.

  • Infrastructure versioning: Terraform's state management and versioning capabilities allow you to track changes to your infrastructure over time and roll back if necessary.

 
# Save the current state as a workspace
terraform workspace new backup-2023-03-24

# Make changes
terraform apply

# If needed, revert to the previous state
terraform workspace select backup-2023-03-24

terraform apply
  • Resource dependency management: When you have complex dependencies between infrastructure resources, Terraform's resource graph ensures proper creation and deletion order.

Decision framework for beginners

When deciding between Ansible and Terraform (or using both), consider these factors:

Project requirements and constraints:

  • Are you primarily provisioning new infrastructure or configuring existing systems?
  • Do you need to manage resources across multiple cloud providers?
  • How important is state tracking and drift detection?

Team expertise:

  • What tools is your team already familiar with?
  • Do you have more expertise in YAML/Python (Ansible) or HCL (Terraform)?
  • How much time can you invest in learning new tools?

Existing infrastructure:

  • Are you managing greenfield deployments or working with existing infrastructure?
  • How much of your infrastructure is cloud-based vs. on-premises?

Cloud vs on-premises considerations:

  • For cloud-heavy environments, Terraform's provider ecosystem offers significant advantages
  • For on-premises or hybrid environments, Ansible's flexibility may be more valuable

A practical approach for many teams is:

  1. Start with Terraform for infrastructure provisioning (especially cloud resources)
  2. Use Ansible for configuration management and application deployment
  3. Develop integration points between the two as needed

Final thoughts

Ansible and Terraform represent different approaches to infrastructure automation that complement each other well.

Terraform's declarative model and state management make it ideal for provisioning cloud infrastructure, while Ansible's procedural approach and extensive module library excel at configuration management and application deployment.

For most organizations, the question isn't whether to use Ansible or Terraform, but how to use them together effectively.

The decision between these tools should be guided by your specific requirements, team expertise, and the nature of your infrastructure.

Thanks for reading!

Author's avatar
Article by
Ayooluwa Isaiah
Ayo is a technical content manager at Better Stack. His passion is simplifying and communicating complex technical ideas effectively. His work was featured on several esteemed publications including LWN.net, Digital Ocean, and CSS-Tricks. When he's not writing or coding, he loves to travel, bike, and play tennis.
Got an article suggestion? Let us know
Licensed under CC-BY-NC-SA

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

Make your mark

Join the writer's program

Are you a developer and love writing and sharing your knowledge with the world? Join our guest writing program and get paid for writing amazing technical guides. We'll get them to the right readers that will appreciate them.

Write for us
Writer of the month
Marin Bezhanov
Marin is a software engineer and architect with a broad range of experience working...
Build on top of Better Stack

Write a script, app or project on top of Better Stack and share it with the world. Make a public repository and share it with us at our email.

community@betterstack.com

or submit a pull request and help us build better products for everyone.

See the full list of amazing projects on github