Learn the differences between Pulumi and Terraform when it comes to support, security, integrations, and functionality for developers and operators.
🚀 Announcing Kubecost Cloud in General Availability: the easiest way to optimize your Kubernetes costs

Pulumi vs Terraform

Like this Article?

Subscribe to our Linkedin Newsletter to receive more educational content

Subscribe now

There was a time when building infrastructure of any reasonable complexity would require a multidisciplinary team of engineers, well versed in designing the likes of networks and database layers. For a while, that was enough, but soon the complexity and necessity of infrastructure provisioning automation led to the birth of the Infrastructure as Code (IaC) design approach. In short, IaC gave us the ability to centralize infrastructure management and state via descriptive definition files.

The adoption of IaC tools was closely related to the rising popularity of cloud computing, which began replacing chunks of classical infrastructure with virtual resources. Soon after, organizations could choose which IaC tool would fit their needs and opt for either vendor-specific or open-source solutions.

This article will aim to describe both Terraform and Pulumi, two popular open-source IaC tools that achieve the same goals in rather different ways. We will also discuss their differences, similarities, pros & cons, and use cases.

Terraform was released by Hashicorp in July 2014 and has since become a go-to solution for IaC. It has a rich feature set, a big community, and plenty of integration with modern-age tooling. Pulumi arrived in June 2018 as the result of a collaboration between former Microsoft executives who saw an opportunity to provide a new take on IaC. Pulumi has been rapidly growing in popularity, and takes a different approach when describing infrastructure: it is more flexible by nature.

Terraform vs Pulumi: are they so different?

How can we differentiate between Terraform and Pulumi? To begin, we’ll explore the functional domains of each tool and cover any similarities or differences within that domain.

Similarities

The following features are present in both tools:

  • within the operational domain:
    • both tools are CLI driven and offer remote execution via a SaaS offering
  • within the development domain:
    • both tools have a declarative engine, which means that each solution is stateful and the engine is there to keep this state reconciled
    • IDE support is present in both, albeit implemented slightly differently (plugins vs native language support)
    • both tools understand the concept of reusability, although Pulumi provides more granularity and flexibility
    • both tools have options for unit, integration and smoke testing, linting and code validation. Pulumi supports these natively and Terraform provides support via a separate toolchain
  • within the security domain:
    • secrets are stored encrypted out-of-the-box for Pulumi and Terraform (if state backend supports it)
    • audit capabilities are available via paid SaaS solutions for both, with Terraform audit logs being slightly more restricted
  • within the support domain:
    • both tools support a wide variety of public and private clouds and SaaS offerings
    • both tools can integrate with popular CI/CD tooling (such as Gitlab or CircleCI)
    • both tools support many different SaaS platforms

Differences

Below, we will present the differences using an easy-to-reference table.

Feature Domain Terraform Pulumi
Operational domain
  • does not need any ‘external’ resource to work
  • by default state, is managed by the user
  • designed to support the structure of large projects
  • partially uses Terraform providers to discover cloud provider APIs
  • by default, state is managed by Pulumi SaaS itself
  • due to its monolithic nature, it can struggle with large-scale projects
Development domain
  • uses proprietary DSL, HashiCorp Configuration Language (HCL) as its base (also for Terraform CDK)
  • declarative language without the ability to step out of its constraints
  • uses general purpose languages like Python or Golang
  • imperative language able to use abstractions and extended logic
Security domain
  • encryption (at rest and in transit) doesn’t come fully out-of-the-box
  • the ability to support new cloud resources is not immediately guaranteed
  • doesn’t fully support Kubernetes outside of Core APIs and Helm (no CRD support or Operator support)
  • everything is encrypted by default
  • same-day support for native providers, can also rely on Terraform modules
  • natively supports the full spectrum of Kubernetes resources, CRDs and has built-in Operator for deployments

Comprehensive Kubernetes cost monitoring & optimization

Terraform vs Pulumi: looking at the differences more closely

In the table above, we grouped and covered differences based on feature domain. Now, let’s examine each domain in detail and discover exactly how Terraform and Pulumi achieve the same thing—but do so differently.

Operational domain

A not-so-well-known fact is that Pulumi has a dependence on Terraform provider schemas. It uses these for each cloud-provider to discover which APIs exist and what configuration options are available. To a degree this makes sense, as schemas are not specific to a given tool. However, this dependency may not be immediately obvious to the end-user. It’s not true to say that Pulumi cannot work without a schema, particularly since the Pulumi ‘native providers’ initiative has been active, but it’s a risk worth knowing. It’s also worth noting that Terraform is not completely independent either, and relies on cloud or SaaS vendor API availability.

One of the more notable differences between these tools is the default way that they handle state. While Terraform relies on a local file (terraform.tfstate), Pulumi uses its own SaaS to store state - which also provides additional features such as change history and statistics recording. The use of SaaS could raise availability and reliability questions. We should mention that both tools do offer a variety of state backends (TF, Pulumi), which does alleviate risk of failure, but requires additional configuration and maintenance.

Another important difference is the suitability of these tools for different project sizes. Pulumi’s concept of ‘stack’ defines the entire infrastructure and is rather monolithic in nature. There’s no dependency between stacks and no way to aggregate them to create homogenous infrastructure. Put another way, once you abstract or extend the definition of the “environment” (to contain a Kubernetes cluster and managed services for example), there is no way to gain granular control over them. For Terraform though, the concept of environment can contain any number of modules or definition files, both reusable and structured. Therefore, Terraform probably provides a better fit for enterprise scale infrastructure.

Development domain

A key factor when choosing between Terraform or Pulumi, might just be the language used. Terraform uses HCL, its own domain-specific language (DSL), that is visually similar to JSON, but with additional capabilities. Unlike JSON, HCL is no stranger to comment sections, value assignments or data structures.

Let’s look at a quick and dirty code excerpt that creates a private S3 bucket. Simple and straightforward, isn’t it?


resource "aws_s3_bucket" "demo"
{
   # Here we create a bucket
   bucket = "demo"
   acl = "private"
   tags = {
	environment = "dev"
	createdBy = "terraform"
   }
}

Now, let’s see how this same task could be achieved using Pulumi. Pulumi uses general purpose languages to describe the desired infrastructure state. You are allowed to use any construct that the programming language supports, whether it’s a class or an interface, a function or a loop. This is why some administrators might call Pulumi an “imperative tool”...But this not entirely accurate, because while its configuration language is indeed imperative, its engine is actually declarative and maintains state.

Below you can see an example—the same as before—but this time implemented as a Python package, which could easily form part of your application code.


import pulumi
import pulumi_aws as aws

bucket = aws.s3.Bucket("demo",
    acl="private",
    tags={
        "environment": "dev",
        "createdBy": "terraform",
    })

These examples are simplistic and are only used to highlight the “DSL vs programming language” difference. The most important take-home is this: you can actually include Pulumi code within your application (and its pipeline) and have them delivered together. Unfortunately, the same cannot be achieved so easily with Terraform.

Security domain

Regarding the security of both tools, it’s essential to remember that by default, Pulumi is exchanging information not only with cloud provider APIs (as does Terraform), but also with its own SaaS. Your infrastructure state is stored there (S3, MySQL) and is encrypted at rest. All communication with the Pulumi SaaS is encrypted in transit using TLS. The diagram below depicts the security architecture of the Pulumi service.

Pulumi security architecture

Image shows the Pulumi security architecture (official security whitepaper)

For Terraform, state can also be stored remotely (with the use of proper backend config) and can be encrypted. By default however, it’s stored locally and is unencrypted - which could raise security concerns. For Terraform’s SaaS offering Terraform Cloud, both the traffic and the state are encrypted.

It’s fair to say that both tools can be used securely, but Pulumi does provide a little more security out-of-the-box. Beyond that, it’s only a matter of setup and price for both SaaS offerings.

Support domain

We have briefly mentioned Pulumi’s native providers, which are useful when supporting new cloud or SaaS features and resources. Pulumi officially promises same-day support for these providers (such as Azure and GCP), while Terraform conversely, make no such claims. In reality, the likelihood of needing urgent support for a new feature are quite low. On the other hand, most Pulumi providers are still classical (non-native) and might have some reliance on Terraform, as previously discussed. It’s fair to say though, that until Pulumi native providers completely replace the classical, we can’t call them leader in cloud provider support.

Another important difference is support for Kubernetes. Rarely nowadays would you see an infrastructure without some distribution or other of Kubernetes, so it makes sense for IaC tools to come with K8’s integration capability. As it stands, Pulumi currently has the superior support for Kubernetes, specifically:

  • full coverage of all Kubernetes APIs
  • support for custom resources definitions (CRDs) directly within Pulumi code
  • has a Kubernetes operator for deploying Pulumi code via CRD definitions
  • can convert Kubernetes manifests into Pulumi code via kube2pulumi

Whether you actually need these features or not may differ, but as long as Terraform supports only the core Kubernetes API, you might find yourself limited for choice if you do.

K8s clusters handling 10B daily API calls use Kubecost

Terraform vs Pulumi: final choice?

Many benefits and drawbacks later, the question remains open - which tool should you choose? The unfortunate, but always best answer is “It depends”. Our suggested points for consideration would be:

  • whose responsibility is the infrastructure? If it will be engineers with development skills, then Pulumi should be considered. If not - Terraform is the more user-friendly option.
  • what size is your infrastructure? If you have hundreds of customers with environments for each, or if you have multi-layered infrastructure, then Terraform is the one. It’s more structured, its usage model can be scaled and dependencies can span across different infra pieces. With Pulumi, you’re locked into the concept of a stack, which is hard to escape from, or abstract to anything larger.
  • is Kubernetes part of your infrastructure? Pulumi offers far better Kubernetes support, plain and simple. If you want your IaC to fully handle infrastructure (and even application) lifecycle, then Pulumi is it. If you have other solutions in place (like GitOps operators or mature CI/CD pipelines), you might opt for the basic support that Terraform provides.

While this article concentrated on comparing technical features, we shouldn’t forget one of the most important factors for those holding the purse strings…The pricing model. Cool features for either solution can come at a price that’s anything but, and that’s likely to have a huge impact on decision makers.

Tie-breaker

If you still haven’t arrived at a cast-iron decision, here are two final thoughts that might sway you one way or the other:

  • Documentation and examples: Terraform generally has the better documentation, complete with relevant examples
  • Security: Pulumi comes with better out-of-the-box options

Conclusion

We have arrived at the end of our journey, during which we tried our best to directly compare Terraform and Pulumi, two popular tools with similar purposes and very different approaches. We hope that this article has been helpful, and has led you to discover something new about both Terraform and Pulumi.

Learn how to manage K8s costs via the Kubecost APIs

Continue reading this series