Skip to content
Infrastructure as Code iac tools 5 min read

Terraform vs Other Tools

Once you have decided you want Infrastructure as Code, the next question is which tool. Terraform and OpenTofu are the default for most teams, but CloudFormation, Pulumi, the AWS CDK, Ansible, and Bicep each win in specific situations. This page is a decision-focused comparison across the dimensions that actually change your day-to-day work: language, cloud support, how state is managed, maturity, and ecosystem. The goal is not to declare a single winner but to help you pick the right tool for your constraints.

The dimensions that matter

Marketing pages compare features; engineering teams should compare trade-offs. Six axes decide almost every IaC choice:

  • Language model — a declarative DSL (HCL, Bicep) versus a general-purpose language (TypeScript, Python, Go, C#).
  • Cloud reach — agnostic provider model versus single-vendor native.
  • State model — an explicit state file you own, service-managed state, or stateless idempotent runs.
  • Maturity and ecosystem — module registries, provider coverage, community answers, and hiring pool.
  • Licensing — permissive open source versus source-available or vendor-controlled.
  • Lifecycle scope — provisioning infrastructure versus configuring what runs inside it.

The comparison at a glance

ToolLanguageCloudsStateMaturity / ecosystemLicense
TerraformHCL (declarative)Agnostic (4000+ providers)Explicit state fileLargest registry, huge communityBSL (source-available)
OpenTofuHCL (declarative)Agnostic, same providersExplicit state fileTerraform-compatible, growingMPL 2.0 (open source)
PulumiTS/Py/Go/C#/JavaAgnostic (reuses TF providers)Managed or self-hostedStrong, smaller than TFApache 2.0
CloudFormationYAML/JSONAWS onlyService-managed stacksMature on AWS, AWS-onlyProprietary (free)
AWS CDKTS/Py/Go/Java/C#AWS onlyCompiles to CloudFormationStrong on AWSApache 2.0
AnsibleYAML (playbooks)AgnosticStateless / idempotentMature, config-focusedGPL 3.0
Bicep / ARMBicep DSL / JSONAzure onlyService-managedMature on Azure, Azure-onlyMIT

Tip: Pulumi can run Terraform providers through its bridge, so “no provider for X” is rarely a reason to rule it out. The real Pulumi-vs-Terraform decision is almost always about language preference, not coverage.

Terraform and OpenTofu: the declarative default

Terraform expresses infrastructure in HCL, computes a diff against an explicit state file, and applies it through provider plugins. OpenTofu is the Linux Foundation fork that stays under the open-source MPL after HashiCorp moved Terraform to the Business Source License in 2023. They share the same language, providers, and workflow, so most configs run unchanged on either binary.

resource "aws_dynamodb_table" "sessions" {
  name         = "user-sessions"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "session_id"

  attribute {
    name = "session_id"
    type = "S"
  }

  ttl {
    attribute_name = "expires_at"
    enabled        = true
  }
}

A plan shows the exact change set before anything touches the cloud:

Output:

Terraform will perform the following actions:

  # aws_dynamodb_table.sessions will be created
  + resource "aws_dynamodb_table" "sessions" {
      + name         = "user-sessions"
      + billing_mode = "PAY_PER_REQUEST"
      + hash_key     = "session_id"
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Pick Terraform/OpenTofu when you want portable skills, the largest module registry, and a declarative model that reads like a description of your infrastructure rather than a program that builds it.

CloudFormation and CDK: the AWS-native pair

CloudFormation is AWS’s own provisioning service. You describe a stack in YAML or JSON, AWS stores and reconciles the state for you, and resources tie directly into AWS IAM and drift detection. The AWS CDK is a layer on top: you write TypeScript, Python, or Java, and it synthesizes CloudFormation templates.

# CDK: write code, synth to CloudFormation, deploy
cdk synth
cdk deploy

Their strength is day-one support for new AWS services and zero state to manage yourself. Their cost is lock-in: neither manages anything outside AWS, and CDK adds a build/synth step plus the leakiness of generating a declarative template from imperative code. Choose them when you are committed to AWS and value native IAM integration over portability.

Pulumi: infrastructure in a real language

Pulumi keeps the agnostic provider model but lets you write infrastructure in a general-purpose language with loops, classes, unit tests, and package managers.

import * as aws from "@pulumi/aws";

const table = new aws.dynamodb.Table("sessions", {
  billingMode: "PAY_PER_REQUEST",
  hashKey: "session_id",
  attributes: [{ name: "session_id", type: "S" }],
  ttl: { attributeName: "expires_at", enabled: true },
});

export const tableName = table.name;

Pulumi shines when your team thinks in code and wants to share abstractions across application and infrastructure repos. The trade-off is that a general-purpose language can hide complexity that a declarative config would force into the open, and the community is smaller than Terraform’s.

Ansible: a different job

Ansible is mostly a configuration-management tool: it shapes what runs inside existing machines (packages, files, services) using idempotent, stateless playbooks. It can provision cloud resources, but that is not its sweet spot. The common pattern is to provision with Terraform and configure with Ansible, rather than treat them as competitors.

Bicep: Azure’s answer to HCL

Bicep is Microsoft’s declarative DSL that transpiles to ARM templates. It is far more readable than raw ARM JSON and integrates tightly with Azure, but like CloudFormation it is single-cloud. If you are all-in on Azure, Bicep is the cleanest native option; if you touch multiple clouds, Terraform’s Azure provider keeps one workflow across all of them.

When to pick each

If you…Choose
Work across multiple clouds and want portable skillsTerraform / OpenTofu
Need a fully open-source license guaranteeOpenTofu
Are all-in on AWS and want native integrationCloudFormation / CDK
Want infrastructure in TypeScript/Python with testsPulumi
Are all-in on AzureBicep
Need to configure software inside running serversAnsible

Best Practices

  • Standardize on one provisioning tool per team; mixing Terraform and CloudFormation for the same resources splits ownership and invites drift.
  • Treat OpenTofu as a first-class, drop-in alternative to Terraform whenever licensing matters to your organization.
  • Provision with a provisioning tool and configure with Ansible or pre-baked images, instead of forcing one tool to do both.
  • Choose Pulumi or CDK for the language, not for coverage; Terraform’s provider registry is the broadest baseline.
  • Prefer cloud-agnostic tooling unless a vendor-only feature genuinely requires native support on launch day.
  • Pin tool and provider versions so plans stay reproducible across machines and over time.
Last updated June 14, 2026
Was this helpful?