Terraform To Pulumi

Terraform To Pulumi

Reading time1 min
#Cloud#DevOps#Infrastructure#Terraform#Pulumi#IaC

Seamlessly Transitioning Infrastructure as Code: A Step-by-Step Guide to Migrating from Terraform to Pulumi

Forget the hype around switching IaC tools. The real value lies in how you migrate without disrupting existing workflows. This guide breaks down the practical steps and nuances of transitioning from Terraform’s declarative style to Pulumi’s imperative approach — mastering the migration rather than just changing the tool.


Infrastructure as Code (IaC) is fundamental in modern development workflows, automating resource provisioning and management at scale. Terraform has long been a staple in this space with its human-readable declarative language (HCL). However, as cloud infrastructures grow more complex and organizations seek deeper integration with existing DevOps toolchains, Pulumi’s multi-language imperative approach is gaining traction.

Pulumi allows you to write infrastructure code using familiar programming languages like TypeScript, Python, Go, or C#. This flexibility empowers developers by integrating IaC more tightly with application code and expanding logic possibilities that are awkward or impossible in declarative formats.

If you’re considering migrating from Terraform to Pulumi, here’s a practical walkthrough to guide your transition smoothly and effectively — avoiding common traps and focusing on continuity.


Why Migrate from Terraform to Pulumi?

Before diving into the how-to, it’s worth revisiting why this change can be a game-changer:

  • Multi-Language Support: Use real programming languages (e.g., Python, TypeScript) instead of HCL.
  • Imperative Programming Model: Write conditional logic and loops natively.
  • Better Code Reuse: Leverage IDE support, linting, debugging, and testing.
  • Unified Tooling: Manage cloud infrastructure alongside application lifecycle code.

Still, migrating entails challenges including understanding Pulumi’s model differences, translating existing state files safely, and adapting your team’s workflows.


Step 1: Audit Your Existing Terraform Infrastructure

Before migrating anything:

  • Identify all Terraform configurations that need migration.
  • List all providers/plugins used.
  • Review dependency graphs, modules in use, backend configurations for state storage.
  • Backup your Terraform state files (terraform.tfstate) — these will be crucial for mapping resources later.

Example:

terraform init
terraform plan
cp terraform.tfstate terraform.tfstate.backup

Step 2: Install Pulumi & Set Up Your Environment

Pulumi needs to be installed on your machines or CI environments.

# Install via npm for JavaScript/TypeScript
npm install -g @pulumi/cli

# Or via Homebrew (macOS)
brew install pulumi

Log in to Pulumi for state management (Cloud Console or self-hosted backend):

pulumi login

Tip: You can also configure Backends like S3 or Azure Blob Storage if needed.


Step 3: Initialize a New Pulumi Project

Create a new project in your desired language.

For example, a TypeScript AWS project:

pulumi new aws-typescript -n my-infra-pulumi
cd my-infra-pulumi

This scaffolds Pulumi.yaml, installs dependencies, and sets up basic files.


Step 4: Import Existing Resources into Pulumi State

Pulumi has a resource import feature that lets you bring existing managed resources under its control without recreating them. This step avoids downtime or conflicts and preserves your actual infrastructure state.

Example of importing an AWS S3 bucket:

pulumi import aws:s3/bucket:Bucket myBucket my-existing-bucket-name

You can script multiple imports based on your Terraform resources list. This results in Pulumi adding these imported resources into its state but does not create any code yet.

Note: You must write resource declarations matching these imports next.


Step 5: Translate Terraform Configurations into Pulumi Code

This is the heart of migration — converting HCL *.tf files into imperative code using the Pulumi SDK for your chosen language.

Key differences to note:

Terraform (HCL)Pulumi (TypeScript example)
Declarative .tf filesImperative JS/Python/Go/C# code
Variables & outputsVariables/constants & functions
ModulesComponent Resources / classes
count, for_eachNative loops (for, .map)
Resource dependenciesHandled by resource references directly

Example conversion from HCL to TypeScript

Terraform HCL

resource "aws_s3_bucket" "bucket" {
  bucket = "my-tf-bucket"
  acl    = "private"

  tags = {
    Environment = "Dev"
    Team        = "Infra"
  }
}

Pulumi TypeScript

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

const bucket = new aws.s3.Bucket("my-pulumi-bucket", {
    bucket: "my-tf-bucket",
    acl: "private",
    tags: {
        Environment: "Dev",
        Team: "Infra",
    },
});

Notice that while keys are similar, the syntax is full JS objects here — allowing for variables, conditionals, loops tightly integrated with logic in your language of choice.


Step 6: Refactor Variables and Outputs

Terraform variable blocks map roughly to parameters/constants or config variables in the target language; outputs map to exported values or stack outputs.

For example:

Terraform

variable "bucket_name" {
  default = "my-tf-bucket"
}

output "bucket_arn" {
  value = aws_s3_bucket.bucket.arn
}

Pulumi

const config = new pulumi.Config();
const bucketName = config.get("bucket_name") || "my-tf-bucket";

const bucket = new aws.s3.Bucket("my-pulumi-bucket", {
    bucket: bucketName,
});

export const bucketArn = bucket.arn;

You will need to create corresponding configuration files for stack variables or pass inputs dynamically using CLI options or environment variables.


Step 7: Test Your New Pulumi Project Locally

Run preview commands and diff outputs before deploying:

pulumi preview         # Shows proposed changes without applying them
pulumi up              # Applies changes interactively with confirmation prompt

Make sure no unintended deletions or recreations happen by cross-checking with your current infra status.

Use pulumi stack export for snapshots of the deployment state if needed for audits or rollbacks.


Step 8: Integrate Into Your CI/CD Pipeline

Update build scripts and pipelines replacing terraform plan/apply steps with pulumi preview/up. Take advantage of Pulumi’s automation API if you want programmatic control over deployments beyond CLI usage.

Example GitHub Actions snippet:

steps:
- uses: actions/checkout@v2
- uses: pulumi/actions@v3
  with:
    command: up --yes 
  env:
    PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}

Tips for a Smooth Migration Experience

  • Incremental Migration: Start small by migrating non-critical resources first.
  • State Management: Avoid dual control — pick either Terraform or Pulumi during migration phases clearly.
  • Team Training: Familiarize engineers with programming idioms used by Pulumi.
  • Leverage Examples: Look into open-source repos with similar cloud infra on Pulumi.
  • Use Component Resources: Encapsulate complex modules as reusable components/classes in code — promoting modularity beyond what Terraforms modules allow.

Wrapping Up

Transitioning from Terraform to Pulumi goes beyond switching tools — it’s embracing a richer programmable model for IaC that enhances flexibility while potentially increasing productivity. With proper planning—auditing current infra, importing states carefully, rewriting configs thoughtfully—and cautious testing/deployment practices you can migrate confidently without disrupting live services or workflows.

The key is mastering the migration process itself so that you truly unlock what modern infrastructure as code can offer today and tomorrow!

Happy coding your cloud infrastructure!


If you found this guide helpful or want example repos/code snippets tailored for your specific provider/language combo, let me know in the comments below!