How Does Terraform Differ From Puppet and Ansible
Published on 01 Nov 2025 by Adam Lloyd-Jones
This is a critical question for understanding the landscape of Infrastructure as Code (IaC) tools, as Terraform, Puppet, and Ansible operate at different layers of the infrastructure management stack and prioritize distinct concerns.
The primary difference lies in their core function: Terraform is a provisioning tool designed to create, update, and manage the infrastructure itself (e.g., VMs, networks, databases), whereas Puppet and Ansible are configuration management tools primarily designed to install, configure, and manage software on existing servers.
Here is a detailed breakdown of how Terraform differs from configuration management tools like Puppet and Ansible across several key dimensions:
Provisioning vs. configuration management (the core distinction)
| Feature | Terraform (Provisioning Tool) | Puppet / Ansible (Configuration Management) |
|---|---|---|
| Primary Goal | Provisioning and Orchestration: Creating the cloud resources, networking topology, and infrastructure components (e.g., VPCs, servers, load balancers). | Configuration and State Management: Installing and managing software packages, user accounts, and specific application configurations on existing servers. |
| Management Focus | High-level infrastructure components (Cloud, SaaS, network, storage). | Low-level server details (files, users, packages, services running within the OS). |
| Typical Workflow | Defines the blueprint for the entire infrastructure, then runs apply to create or modify it. |
Connects to an already-created server (via agent or SSH) and executes steps (recipes or playbooks) to configure its operating system and installed software. |
The need for Terraform (provisioning) often comes before the need for Puppet or Ansible (configuration), as the configuration tools need servers to exist before they can configure them.
Declarative vs. procedural language style
This is one of the most significant architectural differences between the tools:
- Terraform (Declarative): Terraform uses a declarative configuration language (HCL) where you define the desired end state of your infrastructure. Terraform’s core engine compares this desired state against the actual current state (tracked in the state file) and automatically figures out the step-by-step procedure required to get from Point A to Point B. This approach allows the system to determine the best way to achieve the desired state. This eliminates the need to write complex migration code.
- Ansible and Chef (Procedural): Ansible and Chef primarily encourage a procedural style, where you write explicit, step-by-step code (playbooks or recipes) that specifies how to achieve the desired end state. If a change is needed, the user must explicitly write the steps to make that change, often manually taking into account the current state of the infrastructure, which can limit code reusability.
The distinction between the Declarative and Procedural (or Imperative) language styles is fundamental to understanding how Infrastructure as Code (IaC) tools like Terraform operate compared to older systems or traditional scripting methods.
Here is a detailed breakdown of the differences, drawing from the provided sources and conversation history:
Core definitions and focus
The difference between declarative and procedural styles centers on what you define versus how you execute it.
| Feature | Declarative Style (e.g., Terraform, CloudFormation, Puppet, Kubernetes YAML) | Procedural/Imperative Style (e.g., Ansible, Chef, Bash/Shell Scripts) |
|---|---|---|
| Focus | Desired End State (The “What”): Describes the configuration and layout of the desired infrastructure. | Execution Steps (The “How”): Specifies the step-by-step instructions (procedures or commands) required to reach a state. |
| Language Use | Primarily uses nouns and adjectives to define entities, attributes, and relationships. | Primarily uses verbs (actions) to explicitly change the state of the system. |
| Example | “I want three large web servers with this database attached.” | “First, check if the server exists. If not, create it. Then, install Apache. Then, configure the firewall rule.”. |
Mechanism of operation and state
The way each style handles the state of the infrastructure is a core differentiator, particularly for change management.
Declarative style (Terraform, HCL, YAML)
The declarative style defines the final configuration, and the underlying IaC tool handles the work of achieving that state.
- Execution Engine Responsibility: Declarative tools (like Terraform) compare the desired state defined in the configuration files (e.g., HCL) with the current actual state of the infrastructure (tracked internally in a state file). The tool then automatically figures out the precise set of changes, or the best way, it needs to perform (add, update, delete) to bring the infrastructure in line with the code. This sequence of required actions is often represented internally using a Directed Acyclic Graph (DAG).
- Idempotency and Drift: Declarative definitions naturally lend themselves to running idempotently. You can safely apply the configuration repeatedly; if something was changed manually outside of the tool (configuration drift), reapplying the definition will automatically correct it.
- Readability and Maintenance: The code is a statement about how you want your infrastructure to look, making it a form of executable documentation that is less likely to go out of date. Reading the declarative code is usually sufficient to determine what is currently deployed and how it is configured, without needing to know the history of every change.
Procedural/imperative style (Ansible, Scripts)
The imperative style requires the user to specify every action needed, which makes complex operations and modifications tricky.
- Explicit Steps: The developer must explicitly write the code specifying how to perform the action. For instance, using PowerShell code imperatively requires defining variables and then executing explicit commands (
New-AzResourceGroup). - Change Management Risk: If you want to make a change, you need to manually figure out and specify the steps required to transition from the current state to the new state. If the current state is constantly changing (mutable infrastructure), procedural code written a week ago might no longer be usable because it was designed to modify a state of the infrastructure that no longer exists.
- State Capture: Procedural code often fails to fully capture the state of the infrastructure. To reason about an imperative codebase (like Ansible or Chef), you often need to know the full history and specific order in which scripts were applied, as a different order could lead to different infrastructure.
Language examples and syntax
Tools utilizing declarative styles often use specialized configuration languages optimized for human readability, even if they are fundamentally machine-interpretable data formats.
- Terraform/HCL: Terraform uses HashiCorp Configuration Language (HCL), which is a declarative configuration language. HCL is structured to be human-readable and is focused on defining the infrastructure components. HCL is distinct from general data formats like JSON or YAML, though HashiCorp created HCL to be machine translatable to JSON and YAML.
- Azure Resource Manager (ARM) Templates: ARM templates also use a declarative mode, where you describe the desired goal state of your application through a JSON file format. They define the inputs and the resources, and Azure Resource Manager provisions them.
- Bicep: Bicep is a domain-specific language (DSL) for Azure that acts as a transparent, declarative abstraction layer on top of ARM templates. When compiled, Bicep files translate into the JSON-based ARM templates.
The procedural style is often found in general-purpose programming or scripting languages, though tools like Ansible attempt to layer conventions on top of a procedural execution model.
The declarative approach preferred by Terraform is likened to ordering food from a menu: you state what you want (a resource, a configuration), and the kitchen (the Terraform engine) figures out how to prepare, manage, and deliver it, regardless of the intermediate steps required. The imperative approach, conversely, is like writing the recipe yourself, detailing every single step—if a mistake occurs or an ingredient changes, you must rewrite the recipe from scratch.
Architecture: agent vs. agentless and master vs. masterless
The deployment architecture defines how the tool communicates with and manages the resources:
| Feature | Terraform | Puppet / Chef (Traditional) | Ansible |
|---|---|---|---|
| Agent Requirement | Agentless: It does not require agent software installed on the managed servers. Terraform operates by making direct API calls to cloud providers (like AWS or Azure) using your credentials. | Agent-Based: Typically requires specialized agent software (e.g., Chef Client, Puppet Agent) to be installed and running on every managed server. | Agentless: Works via a push model by connecting directly to the managed server over SSH. |
| Master Server | Masterless: Terraform operates as a single binary (client-only) and relies on the cloud provider’s own API servers (which are like managed masters). | Master Required (By Default): Typically requires running a dedicated master server (e.g., Puppetmaster or Chef Server) to store configuration state and distribute updates. | Masterless: Operates client-only and connects over SSH. |
The masterless, agentless architecture of Terraform (and Ansible) results in fewer moving parts and failure modes compared to the typical agent/master architecture of Puppet and Chef.
Portability and vendor support
- Terraform: It is intentionally vendor-agnostic and can interact with virtually any cloud provider, virtualization platform, or even third-party services using its extensive provider ecosystem. Terraform uses one language (HCL) to create infrastructure across all major cloud platforms (AWS, Azure, Google Cloud, and more).
- Puppet/Ansible: While they also support multiple platforms, their primary domain historically has been operating system configuration, not cloud provisioning. When integrating these tools with the cloud, they often focus on configuring what Terraform has already provisioned.
Summary of how they work together
In a modern Infrastructure as Code workflow, these tools are often used together to cover the full spectrum of deployment:
- Terraform creates the infrastructure: Terraform provisions the network, the Virtual Machines (VMs), and the database instances.
- Ansible/Puppet configure the VMs: Once the VM is running, a configuration tool like Ansible or Puppet is typically run to install application dependencies, configure system settings, manage users, and deploy the application code onto the newly provisioned server.
For example, an organization might use Terraform to provision the servers and then run Ansible or Chef to configure each one. However, some modern approaches favor server templating tools (like Docker or Packer) to create immutable server images with all configuration baked in, which reduces the need for constant, post-provisioning configuration management via tools like Ansible or Puppet.
Related Posts
- An introduction to Puppet
- Should I be worried about moving to Opentofu from Terraform
- Terraform modules explained - your ultimate guide to reusable components and devops automation
- The Diverging Paths of Infrastructure as Code: How OpenTofu Handles State Management Differently from Terraform
- Making infrastructure as code (IaC) better: A modular and scalable approach
- HAProxy Load Balancing with Docker: A Complete Guide to Building a Two-Node Cluster
- Zero Downtime Evolution: How Blue Green Deployment and Dynamic Infrastructure Power Service Continuity
- A practical guide to Azure Kubernetes Service (AKS) deployment
- Docker Networking Made Simple: What Every Beginner Needs to Know
- Multiple Environments in Docker
- From Clickops to Gitops Scaling Iac Maturity
- The Essential Guide to Docker for Packaging and Deploying Microservices
- Understanding OpenTofu config files
- What are the different files used by Terraform?
- How Infrastructure as Code delivers unprecedented time savings
- ClickOps vs. IaC: Why Terraform wins in the modern cloud era
- What is Terraform?
- Module 4: Modularisation and Reusability in Terraform
- Module 2: Provisioning Core Azure Resources With Terraform
- Module 1: Introduction to Terraform on Azure
- Azure Terraform Tutorial Series From Zero to Production
- Mastering Terraform variables, outputs and local values for dynamic infrastructure
- Deploy Azure like a pro: your first Terraform main.tf made simple
- The function of the main.tf file
- Iterating over providers in Opentofu
- Why developers are moving away from Terraform—and what they're choosing instead
- What is OpenTofu? Terraform’s open-source alternative
