Terraform vs Pulumi: Choosing Your Infrastructure as Code Tool


Infrastructure as Code has moved from “nice to have” to “table stakes” for any team managing cloud resources. The two leading tools — Terraform and Pulumi — take fundamentally different approaches to the same problem. After using both in production, here’s my take on when to choose each.

The Core Difference

Terraform uses HCL (HashiCorp Configuration Language), a domain-specific language designed specifically for infrastructure definitions. Pulumi lets you write infrastructure code in general-purpose programming languages: TypeScript, Python, Go, C#, or Java.

This isn’t just a syntax preference. It affects how you think about and structure your infrastructure code.

In Terraform:

resource "aws_s3_bucket" "data" {
  bucket = "my-app-data-${var.environment}"

  tags = {
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

In Pulumi (TypeScript):

const bucket = new aws.s3.Bucket("data", {
  bucket: `my-app-data-${environment}`,
  tags: {
    Environment: environment,
    ManagedBy: "pulumi",
  },
});

For simple resources, they look remarkably similar. The differences emerge when things get complex.

Where Terraform Wins

Ecosystem maturity. Terraform has been around since 2014. The provider ecosystem is enormous — over 3,000 providers covering virtually every cloud service and third-party API. If a service has an API, there’s probably a Terraform provider for it.

Hiring and documentation. More infrastructure engineers know Terraform than Pulumi. Job listings mentioning Terraform outnumber Pulumi mentions by roughly 10 to 1. The documentation, blog posts, and Stack Overflow answers for Terraform are extensive.

HCL is intentionally limited. This sounds like a drawback, but it’s actually a feature. HCL prevents you from writing complex logic in your infrastructure definitions. You can’t embed a REST API client in your Terraform code (well, you can, but it’s deliberately difficult). This constraint keeps infrastructure code focused on declaring desired state rather than implementing behaviour.

Plan readability. terraform plan produces output that even non-developers can read. It clearly shows what will be created, modified, or destroyed. This makes it easier to get approval from security teams and managers who need to understand infrastructure changes.

Where Pulumi Wins

Complex logic. When your infrastructure requires conditional creation, loops with transformation, or dynamic resource generation, Pulumi shines. Need to create a VPC with a variable number of subnets, each with different CIDR calculations? In TypeScript, that’s a for loop. In Terraform, it’s a for_each with cidrsubnet functions and locals blocks that quickly become hard to follow.

const subnets = availabilityZones.map((az, index) => {
  return new aws.ec2.Subnet(`subnet-${az}`, {
    vpcId: vpc.id,
    cidrBlock: `10.0.${index}.0/24`,
    availabilityZone: az,
  });
});

Testing. Pulumi infrastructure code is testable with standard unit testing frameworks. You can write Jest tests for your TypeScript infrastructure, pytest tests for your Python infrastructure. Terraform testing has improved with the terraform test command, but it’s still more limited than what’s available in general-purpose languages.

Sharing and abstraction. Pulumi components are classes that you can package, version, and distribute through standard package registries (npm, PyPI). Creating reusable infrastructure abstractions feels natural when you’re working in a language designed for abstraction.

Secret management. Pulumi encrypts secrets in state by default. Terraform stores them in plaintext in the state file, requiring you to encrypt the state file itself or use external secret management.

The OpenTofu Factor

The elephant in the room is HashiCorp’s licence change in 2023 and the subsequent fork to OpenTofu. If licence concerns matter to your organisation, OpenTofu provides a BSL-free alternative that’s compatible with existing Terraform code.

In practice, the fork hasn’t caused the disruption some predicted. Most teams are either using Terraform through HashiCorp Cloud Platform (where the licence doesn’t matter) or have switched to OpenTofu without significant issues. The provider ecosystem works with both.

When I Recommend Each

Choose Terraform when:

  • Your team has existing Terraform expertise
  • Your infrastructure is relatively straightforward (standard cloud resources, well-known patterns)
  • You value a large ecosystem of community modules and providers
  • You want infrastructure code that’s readable by non-developers

Choose Pulumi when:

  • Your team is stronger in application development than infrastructure
  • Your infrastructure requires complex logic (dynamic resource generation, conditional creation, computed values)
  • You want to use the same testing frameworks for infrastructure and application code
  • Secret management is a priority

For small teams and startups, I lean toward Pulumi with TypeScript. The ability to use one language for both application and infrastructure code reduces context switching. Many Australian businesses building their first cloud infrastructure have found that working with AI strategy support teams helps them make these tooling decisions based on their specific team composition and growth plans.

For larger organisations with established infrastructure teams, Terraform’s maturity and wider talent pool often outweigh Pulumi’s ergonomic advantages.

The Honest Answer

Both tools are production-ready and well-maintained. The worst choice is spending three months evaluating tools instead of provisioning infrastructure. Pick the one that fits your team’s skills, use it consistently, and move on to solving actual business problems.