Infrastructure as Code: Terraform vs Pulumi vs Ansible
Compare Terraform, Pulumi, and Ansible for Infrastructure as Code. Learn when to use each tool and how they complement each other in modern DevOps workflows.
Key takeaways
- Compare Terraform, Pulumi, and Ansible for Infrastructure as Code.
- Learn when to use each tool and how they complement each other in modern DevOps workflows.
On this page
Infrastructure as Code: Terraform vs Pulumi vs Ansible#
Infrastructure as Code (IaC) is essential for modern DevOps. This guide compares three popular tools: Terraform, Pulumi, and Ansible, helping you choose the right one for your needs.
Overview Comparison#
| Feature | Terraform | Pulumi | Ansible |
|---|---|---|---|
| Language | HCL | General-purpose | YAML/Python |
| State Management | Built-in | Built-in | Stateless |
| Cloud Support | Excellent | Excellent | Good |
| Learning Curve | Medium | Medium-High | Low |
| Best For | Cloud provisioning | Multi-cloud, complex logic | Configuration management |
Terraform#
Terraform uses HashiCorp Configuration Language (HCL) and is the most popular IaC tool.
Example: AWS EC2 Instance#
# main.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
tags = {
Name = "WebServer"
Environment = "Production"
}
}
output "instance_ip" {
value = aws_instance.web.public_ip
}
Pros:
- Mature and stable
- Excellent documentation
- Large community
- Strong state management
- Multi-cloud support
Cons:
- Limited programming constructs
- HCL can be verbose
- State file management complexity
Pulumi#
Pulumi allows you to write IaC in familiar programming languages.
Example: AWS EC2 Instance (TypeScript)#
import * as aws from "@pulumi/aws";
const instance = new aws.ec2.Instance("web", {
ami: "ami-0c55b159cbfafe1f0",
instanceType: "t3.micro",
tags: {
Name: "WebServer",
Environment: "Production",
},
});
export const instanceIp = instance.publicIp;
Example: AWS EC2 Instance (Python)#
import pulumi
import pulumi_aws as aws
instance = aws.ec2.Instance("web",
ami="ami-0c55b159cbfafe1f0",
instance_type="t3.micro",
tags={
"Name": "WebServer",
"Environment": "Production",
}
)
pulumi.export("instance_ip", instance.public_ip)
Pros:
- Use familiar languages (TypeScript, Python, Go, etc.)
- Better for complex logic
- Strong typing and IDE support
- Good for application developers
Cons:
- Smaller community than Terraform
- Requires programming knowledge
- Can be overkill for simple infrastructure
Ansible#
Ansible is primarily a configuration management tool but can also provision infrastructure.
Example: EC2 Instance#
# playbook.yml
---
- name: Create EC2 instance
hosts: localhost
gather_facts: no
tasks:
- name: Launch instance
ec2_instance:
name: webserver
image_id: ami-0c55b159cbfafe1f0
instance_type: t3.micro
tags:
Name: WebServer
Environment: Production
register: ec2
- name: Display instance IP
debug:
msg: "Instance IP: {{ ec2.instances[0].public_ip_address }}"
Pros:
- Agentless (SSH-based)
- Easy to learn (YAML)
- Excellent for configuration management
- Large module library
- Idempotent operations
Cons:
- Weaker state management
- Not ideal for complex cloud provisioning
- Can be slow for large infrastructures
When to Use Each#
Use Terraform When:#
- Provisioning cloud infrastructure
- Need strong state management
- Working with multiple cloud providers
- Team is comfortable with HCL
Use Pulumi When:#
- Team has strong programming skills
- Need complex logic in infrastructure
- Want type safety and IDE support
- Building reusable infrastructure libraries
Use Ansible When:#
- Managing server configuration
- Need to configure existing infrastructure
- Prefer declarative YAML
- Working with mixed environments
Combining Tools#
Many teams use multiple tools together:
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Terraform │────▶│ Infrastructure│────▶│ Ansible │
│ (Provision) │ │ (Created) │ │ (Configure)│
└─────────────┘ └──────────────┘ └─────────────┘
Workflow Example#
- Terraform provisions infrastructure
- Ansible configures the provisioned servers
- Pulumi (optional) handles complex application deployments
Best Practices#
Terraform#
- Use modules for reusability
- Implement remote state
- Use workspaces for environments
- Version control all code
- Review plans before applying
Pulumi#
- Organize projects by environment
- Use stacks for different environments
- Leverage programming features (loops, functions)
- Write tests for infrastructure code
Ansible#
- Use roles for organization
- Keep playbooks idempotent
- Use inventories for different environments
- Leverage Ansible Vault for secrets
Migration Strategies#
Terraform to Pulumi#
# Use terraform-bridge to convert
pulumi import --from terraform main.tf
Ansible to Terraform#
- Use Terraform for new infrastructure
- Keep Ansible for configuration
- Gradually migrate playbooks
Conclusion#
There's no one-size-fits-all solution. Choose based on:
- Your team's skills
- Infrastructure complexity
- Cloud provider requirements
- Existing tooling
Many successful teams use Terraform for provisioning and Ansible for configuration, while Pulumi is gaining traction for teams with strong programming backgrounds.
Get the DevOps Troubleshooting Cheat Sheet
Subscribe and get our free one-page reference for the errors that eat an afternoon — CrashLoopBackOff, OOMKilled, Terraform state locks, and more — plus new guides as we publish them.
Linux System Monitoring with Prometheus and Grafana
Set up comprehensive Linux system monitoring using Prometheus and Grafana. Monitor CPU, memory, disk, network, and application metrics with beautiful dashboards.
Fine-tuning Large Language Models: A Practical Guide
Learn how to fine-tune LLMs like Llama 2, Mistral, and GPT models for your specific use case. Includes LoRA, QLoRA, and full fine-tuning techniques.
More from Infrastructure
Explore more articles in this category
Cloudflare's Clef: When a Decision Model Beats an LLM Call
Most moderation, routing, and triage calls aren't generation problems. Clef proves it by answering in 38.8 milliseconds instead of seconds.
Perplexity Left DynamoDB for CobbleDB: When Should You?
Perplexity built its own key-value store because DynamoDB's read path and bill stopped fitting 50 KB search items. Here is the checklist for when leaving is justified.
The Terraform Lock File Is Code: Review It Before You Init
A DPRK-linked group is mailing DevOps candidates Terraform take-home repos whose lock file points at a fake registry. terraform init then runs the attacker's provider.
You might have missed
Evergreen posts worth revisiting.