Pulumi Terraform Migration Architecture

The transition from HashiCorp Terraform to Pulumi represents a strategic shift from a declarative, domain-specific language (DSL) toward a general-purpose, imperative programming model for infrastructure as code. Over the last two years, a growing trend of cloud development teams has shifted toward Pulumi. This migration is typically driven by teams that have made substantial investments in Terraform but have encountered systemic ceilings regarding expressivity, productivity, scalability, or reliability. The core tension lies in the contrast between Terraform's HashiCorp Configuration Language (HCL), which is declarative, and Pulumi's approach, which allows the use of standard programming languages.

While Terraform remains a dominant force in the market, including a massive ecosystem of providers, the shift toward Pulumi allows organizations to leverage full integrated development environment (IDE) support, native testing frameworks, and the ability to define infrastructure using classes and functions. This transition is not merely a change in syntax but a change in operational philosophy, moving from a static configuration file to a dynamic program. This comprehensive analysis explores the technical mechanisms for migrating from Terraform to Pulumi, the architectural paths available, and the tools used to bridge the gap between these two infrastructure paradigms.

The Imperative vs. Declarative Paradigm Shift

The fundamental difference between Terraform and Pulumi is the language used to define the desired state of the cloud. Terraform utilizes the HashiCorp Configuration Language (HCL). This is a declarative language, meaning the user describes what the final state should look like, and Terraform determines how to achieve it. While HCL is efficient for simple configurations, it can become cumbersome when implementing complex logic, conditional loops, or dynamic resource generation.

Pulumi adopts an imperative approach, enabling the use of familiar, high-level programming languages. This allows developers to apply the same software engineering rigor to their infrastructure that they apply to their application code.

  • Supported Languages
    Pulumi allows for the definition of infrastructure in TypeScript, Python, Go, C#, and Java.

  • Impact of Language Choice
    By using these languages, users gain access to full IDE support, including autocomplete and type checking, which significantly reduces the error rate during the development phase. Furthermore, the ability to use native testing frameworks such as Jest for TypeScript, pytest for Python, or Go testing allows for the implementation of unit and integration tests for infrastructure, which is a significant leap over traditional HCL validation.

  • Logic and Expressivity
    With an imperative approach, users have far greater control over how infrastructure is defined. Complex logic that is difficult or impossible to express in HCL—such as complex loops, conditional resource creation based on external API calls, or advanced data manipulation—can be written using standard programming constructs.

  • Readability Trade-offs
    While the imperative approach increases power, it can lead to a decrease in readability. Terraform's HCL is often more concise and easier for a non-developer to scan to understand the general architecture. Pulumi code, being a full program, can become more verbose or abstract, depending on how the developer implements their classes and functions.

The Pulumi Convert Ecosystem

For teams managing large-scale infrastructure, the prospect of manually rewriting thousands of lines of HCL is a significant barrier. To address this, Pulumi has integrated comprehensive conversion capabilities directly into its toolchain.

Historically, Pulumi offered a standalone tool called tf2pulumi designed to convert small snippets of HCL into Pulumi code. However, as of version v3.71.0, this capability has been absorbed into the main Pulumi CLI.

  • The pulumi convert Command
    The current method for migrating whole projects is the pulumi convert --from terraform command. This is no longer a separate utility but a core function of the Pulumi CLI.

  • Technical Capabilities of the Converter
    The converter is designed to handle complex Terraform projects. It includes support for:

  • Terraform modules, allowing for the conversion of modularized infrastructure.
  • Core features of Terraform 1.4.
  • The majority of Terraform built-in functions.

  • Target Languages
    The converter translates HCL into Pulumi programs written in TypeScript, Python, Go, or C#. This allows teams to choose the language that best aligns with their existing development stack.

  • Operational Impact
    The primary impact of the pulumi convert tool is the drastic reduction in migration time. Instead of a manual rewrite, the tool automates the translation of HCL configuration into Pulumi programs and handles the translation of Terraform state files into Pulumi import files.

  • Installation and Setup
    To utilize the converter, users must first install the Pulumi CLI. The converter can be installed through Pulumi's plugin system using the following command:

pulumi plugin install converter terraform

Alternatively, users can build the pulumi-converter-terraform tool from source or download binary releases hosted on GitHub.

Migration Architectural Paths

Migrating from Terraform to Pulumi does not have to be an all-or-nothing event. Depending on the risk tolerance and the size of the infrastructure, organizations can choose from three primary architectural paths.

  • Full Conversion
    This path involves using the pulumi convert command to automatically translate the entire HCL codebase and state. The flow is as follows:
  1. Convert HCL to Code.
  2. Import State.
  3. Validate and Test.
  4. Production Deployment.
  • Gradual Migration
    This approach allows Terraform and Pulumi to coexist. Infrastructure is migrated module by module, which reduces the risk of a catastrophic failure during the transition. The flow involves:
  1. Coexisting TF and Pulumi.
  2. Migrating Module by Module.
  3. Validation and Testing.
  4. Production Deployment.
  • State Import Only
    In this scenario, the user focuses only on the existing resources. They import the current state and then write new Pulumi code to manage those resources. The flow is:
  1. Import Existing Resources.
  2. Write New Pulumi Code.
  3. Validation and Testing.
  4. Production Deployment.

Coexistence and State Referencing

A critical requirement for many organizations is the ability to use Pulumi while still maintaining some infrastructure in Terraform. This "coexistence" phase allows for a phased migration.

  • Referencing Terraform State
    When Pulumi needs to interact with infrastructure still managed by Terraform, it can reference the .tfstate file. This is essential when Terraform exports critical output variables, such as VPC IDs, IP addresses, or Kubernetes kubeconfig files, that the Pulumi project needs to function.

  • The RemoteStateReference Resource
    Pulumi provides the RemoteStateReference resource, which allows users to reference output variables exported from a Terraform project. This creates a bridge where Pulumi can "read" the state of Terraform-managed resources without taking over management of them.

  • Technical Implementation of Coexistence
    There are several ways to handle this in practice:

  • Option 1: Lookup by Tag
    Using the Pulumi AWS provider, a resource can be located based on tags.

const existingVpc = aws.ec2.getVpc({ filters: [{ name: "tag:ManagedBy", values: ["terraform"] }] });

  • Option 2: Lookup by ID
    A Pulumi project can use a configuration file to store the ID of a Terraform-managed resource.

const config = new pulumi.Config();
const tfVpcId = config.require("terraformVpcId");
const existingVpcById = aws.ec2.getVpc({ id: tfVpcId });

Once the reference is established, Pulumi can create new resources that depend on the Terraform resources. For example, creating a new subnet within a Terraform-managed VPC:

const newSubnet = new aws.ec2.Subnet("pulumi-managed-subnet", { vpcId: existingVpc.then(v => v.id), cidrBlock: "10.0.100.0/24", tags: { Name: "pulumi-managed-subnet", ManagedBy: "pulumi" } });

Resource-Level Migration and State Transfer

For a permanent migration, resources must be moved from the Terraform state to the Pulumi state without destroying and recreating the physical cloud resources.

  • State Removal from Terraform
    The first step is to remove the resource from the Terraform state. This tells Terraform to stop tracking the resource, but it does not delete the resource from the cloud provider.

cd terraform/
terraform state rm aws_subnet.old_subnet

  • Resource Import into Pulumi
    The second step is to import that specific resource into Pulumi using the pulumi import command.

cd ../pulumi/
pulumi import aws:ec2/subnet:Subnet old-subnet subnet-0123456789abcdef0

  • Automation via Migration Scripts
    To handle large volumes of resources, developers can create Python scripts to orchestrate the transfer. These scripts typically define a list of resources to migrate, including the Terraform address, the Pulumi type, the Pulumi name, and the actual resource ID.

Example script structure:

```python

!/usr/bin/env python3

migrate_resources.py - Automate resource migration

"""
Migration script to move resources from Terraform to Pulumi.
This script orchestrates the state transfer without affecting
actual cloud resources.
"""
import subprocess
import json
import sys

Define resources to migrate

Format: (terraformaddress, pulumitype, puluminame, resourceid)

RESOURCESTOMIGRATE = []
```

Bridging the Provider Gap

One of the most significant differences between the two ecosystems is the number of available providers. Terraform has a vast library of 3,511 providers, whereas Pulumi has 125. While some Terraform providers are for hobbyist projects (e.g., ordering pizza or Minecraft blocks), the gap remains substantial for professional use cases.

To address this, Pulumi utilizes a "bridge" system that allows Pulumi to leverage the work done in the Terraform ecosystem.

  • Pulumi Terraform Bridge
    The Pulumi Terraform Bridge is a tool that creates Pulumi SDKs based on a Terraform provider schema. This allows Pulumi to support resources that were originally designed for Terraform.

  • Terraform Bridge Provider Boilerplate
    This is a template provided by Pulumi for building new Pulumi providers based on an existing Terraform provider.

  • Design Time vs. Runtime
    The Pulumi Terraform Bridge operates in two distinct phases:

  • Design Time
    During this phase, the bridge inspects the Terraform provider schema and automatically generates Pulumi SDKs in multiple languages. This ensures that the Pulumi user has the correct types and properties available in their IDE.

  • Runtime
    At runtime, the bridge connects Pulumi to the underlying cloud resource via the Terraform provider schema. This allows the Terraform provider schema to continue performing validation and calculating the differences (diffs) between the state stored in Pulumi and the actual state of the resource in the cloud.

  • Technical Distinction
    A critical technical point is that the Pulumi Terraform Bridge does not use the Terraform provider binaries directly; it uses the schema to facilitate communication and validation.

Operational and Technical Advantages of Migration

The decision to migrate from Terraform to Pulumi is often based on a set of operational improvements that exceed the mere change in language.

  • Programming Language Benefits
    The use of TypeScript, Python, Go, C#, and Java provides several immediate advantages:
  • Native testing frameworks (Jest, pytest, Go testing) allow for a "Test-Driven Infrastructure" approach.
  • Reusable components can be created as real classes and functions, allowing for better abstraction and DRY (Don't Repeat Yourself) principles than Terraform modules.
  • There is no need to learn a new DSL for complex logic.

  • Operational Improvements
    Pulumi introduces several built-in operational features that improve the lifecycle of infrastructure:

  • Unified State Management: Options for Pulumi Cloud or self-hosted backends.
  • Secrets Management: Built-in secrets management with automatic encryption, reducing the risk of leaking sensitive data in state files.
  • Policy as Code: Through CrossGuard, Pulumi allows the definition of policies that are enforced during the deployment process, ensuring compliance.
  • Drift Detection: Enhanced mechanisms for detecting and remediating drift between the defined state and the actual cloud state.

Summary of Technical Specifications and Comparisons

The following table compares the core attributes of the two systems based on the migration context.

Feature Terraform Pulumi
Primary Language HCL (Declarative) TS, Python, Go, C#, Java (Imperative)
Provider Count 3,511 125
Tooling for Migration N/A pulumi convert, tf2pulumi
IDE Support Limited (DSL) Full (Language native)
Testing HCL Validation Jest, pytest, Go testing
State Referencing Native .tfstate RemoteStateReference
Policy Management Sentinel CrossGuard

Analysis of Migration Outcomes

The migration from Terraform to Pulumi is a transition from a configuration-centric model to a software-centric model. The primary success factor in these migrations is the management of state. By utilizing the pulumi convert command, teams can eliminate the manual labor of translation, but the operational success depends on the chosen migration path.

For high-risk production environments, the gradual migration path—where Pulumi and Terraform coexist using RemoteStateReference—is the most viable. This allows teams to validate Pulumi's behavior on a per-module basis before fully decommissioning the Terraform state. For teams starting with smaller projects or those moving to a new environment, the full conversion path is highly efficient.

The existence of the Pulumi Terraform Bridge is the most critical architectural component for long-term sustainability. Without it, the provider gap would be an insurmountable wall. By leveraging the Terraform provider schema, Pulumi effectively subsumes the ecosystem of Terraform while providing the expressivity of a general-purpose programming language. The final outcome is an infrastructure pipeline that is more testable, more scalable, and more aligned with modern DevOps practices.

Sources

  1. Converting Full Terraform Programs to Pulumi
  2. Pulumi Converter Terraform GitHub
  3. Adopting Pulumi from Terraform
  4. Pulumi Terraform Provider Analysis
  5. Pulumi Terraform Migration Guide 2026

Related Posts