New: Use Terraform Modules in Pulumi Without Conversion

Posted on

Today, we’re excited to announce a major advancement in Pulumi’s mission to make modern infrastructure as code accessible to every developer: direct support for executing Terraform modules. This new capability addresses one of the most significant challenges our users face when migrating from Terraform to Pulumi—complex projects with extensive module dependencies.

The Path to Modern Infrastructure as Code

At Pulumi, we believe the ideal infrastructure as code experience leverages the full power of modern programming languages, AI-assisted development, and cloud-native tooling. Our vision is that every team should be able to write infrastructure code in their preferred language—TypeScript, Python, Go, C#, or Java—with full IntelliSense, testing capabilities, and AI-powered assistance.

However, we also understand the reality that many organizations have invested years building extensive Terraform module estates. These modules often contain critical business logic, compliance configurations, and battle-tested patterns that teams can’t always rewrite overnight.

This new capability bridges that gap, giving you the best of both worlds: the ability to start new projects in Pulumi immediately while preserving your existing Terraform modules until you’re ready to migrate them.

Strategic Migration Approach

Here’s how we recommend teams approach this transition:

Phase 1: New Projects in Pulumi Start all new infrastructure projects in Pulumi to immediately gain the benefits of modern IaC—better developer experience, AI assistance, and cloud-native tooling.

Phase 2: Incremental Module Migration Use the new Terraform module support to bring existing modules into Pulumi projects without rewriting them. This gives you immediate access to Pulumi Cloud’s state management, deployment workflows, and team collaboration features across all your IaC.

Phase 3: Full Migration (When Ready) Gradually migrate your Terraform modules to native Pulumi components as time and resources permit. With AI-assisted development tools making this easier than ever, you can modernize at your own pace.

This approach eliminates the “big bang” migration risk while ensuring you’re not stuck with legacy tooling for new projects.

What This Means for Your Team

This isn’t just a technical feature—it’s a strategic enabler for teams looking to modernize their infrastructure practices. Here’s what this announcement means:

For Terraform Users: You can now migrate to Pulumi incrementally, keeping your existing modules intact while gaining access to Pulumi’s powerful programming language features, better state management, and enhanced developer experience.

For Platform Teams: You can standardize on Pulumi for new infrastructure while seamlessly incorporating existing Terraform modules, reducing migration risk and accelerating adoption.

For DevOps Engineers: You get the best of both worlds—the reliability of proven Terraform modules with Pulumi’s superior tooling, testing capabilities, and deployment workflows.

How It Works

The new feature consists of three key components:

1. Direct Module Execution

The pulumi package add terraform-module command now supports modules from Terraform and OpenTofu registries, as well as locally managed modules. This is powered by our new terraform-module provider, which orchestrates Terraform execution while maintaining the full Pulumi lifecycle.

2. Enhanced Conversion Support

Our pulumi convert --from terraform tool now supports a special annotation // @pulumi-terraform-module <pulumi-package-name> that tells the converter to execute modules directly rather than attempting to translate them. This preserves your existing module logic while enabling Pulumi’s benefits.

3. Configuration Synchronization

Pulumi providers now expose helper methods like awsProvider.terraformConfig() to keep configuration consistent between Pulumi and Terraform providers, eliminating the need to maintain duplicate configuration.

Real-World Impact

Let me walk you through a practical example that demonstrates the power of this integration.

First, install the latest version of the Pulumi CLI (v3.178.0 or later is required) and create a new Pulumi TypeScript project using pulumi new typescript.

Setting Up a VPC Module

Next, add a Terraform module to your Pulumi project:

$ pulumi package add terraform-module terraform-aws-modules/vpc/aws 6.0.1 vpcmod
Successfully generated a Nodejs SDK for the vpcmod package at /Users/anton/tmp/2025-06-23/blog/sdks/vpcmod

Pulumi automatically generates a local SDK with full TypeScript support:

$ ls sdks/vpcmod
README.md       index.ts        node_modules    provider.ts     tsconfig.json   utilities.ts
bin             module.ts       package.json    scripts         types

And links it into your project in package.json:

{
    "dependencies": {
        "@pulumi/vpcmod": "file:sdks/vpcmod"
    }
}

Using the Module in Your Code

Now you can use the module with full IntelliSense support:

import * as pulumi from "@pulumi/pulumi";
import * as vpcmod from '@pulumi/vpcmod';

const vpc = new vpcmod.Module("test-vpc", {
    azs: ["us-west-2a", "us-west-2b"],
    name: `test-vpc-${pulumi.getStack()}`,
    cidr: "10.0.0.0/16",
    public_subnets: [
        "10.0.1.0/24",
        "10.0.2.0/24",
    ],
    private_subnets: [
        "10.0.3.0/24",
        "10.0.4.0/24",
    ],
    enable_nat_gateway: true,
    single_nat_gateway: true,
});

export const publicSubnets = vpc.public_subnets;
export const privateSubnets = vpc.private_subnets;

Seamless Deployment

When you run pulumi up, Pulumi orchestrates the Terraform module execution while providing its signature preview and deployment experience:

Previewing update (dev)

View in Browser (Ctrl+O): https://app.pulumi.com/anton-pulumi-corp/anton-blog/dev/previews/5851682a-a3e3-4f47-a50e-3d7b4f4e6c34

     Type                                         Name                                                    Plan
 +   pulumi:pulumi:Stack                          anton-blog-dev                                          create
 +   └─ vpcmod:index:Module                       test-vpc                                                create
 +      ├─ vpcmod:tf:aws_route_table_association  module.test-vpc.aws_route_table_association.private[0]  create
 +      ├─ vpcmod:tf:aws_subnet                   module.test-vpc.aws_subnet.private[1]                   create
 +      ├─ vpcmod:tf:aws_route_table_association  module.test-vpc.aws_route_table_association.public[1]   create
 +      ├─ vpcmod:tf:aws_subnet                   module.test-vpc.aws_subnet.private[0]                   create
 +      ├─ vpcmod:tf:aws_route_table              module.test-vpc.aws_route_table.private[0]              create
 +      ├─ vpcmod:tf:aws_subnet                   module.test-vpc.aws_subnet.public[1]                    create
 +      ├─ vpcmod:tf:aws_nat_gateway              module.test-vpc.aws_nat_gateway.this[0]                 create
 +      ├─ vpcmod:tf:aws_route                    module.test-vpc.aws_route.public_internet_gateway[0]    create
 +      ├─ vpcmod:tf:aws_route                    module.test-vpc.aws_route.private_nat_gateway[0]        create
 +      ├─ vpcmod:tf:aws_default_network_acl      module.test-vpc.aws_default_network_acl.this[0]         create
 +      ├─ vpcmod:tf:aws_default_route_table      module.test-vpc.aws_default_route_table.default[0]      create
 +      ├─ vpcmod:tf:aws_subnet                   module.test-vpc.aws_subnet.public[0]                    create
 +      ├─ vpcmod:tf:aws_internet_gateway         module.test-vpc.aws_internet_gateway.this[0]            create
 +      ├─ vpcmod:tf:aws_vpc                      module.test-vpc.aws_vpc.this[0]                         create
 +      ├─ vpcmod:tf:aws_default_security_group   module.test-vpc.aws_default_security_group.this[0]      create
 +      ├─ vpcmod:tf:aws_route_table              module.test-vpc.aws_route_table.public[0]               create
 +      ├─ vpcmod:tf:aws_eip                      module.test-vpc.aws_eip.nat[0]                          create
 +      ├─ vpcmod:tf:aws_route_table_association  module.test-vpc.aws_route_table_association.public[0]   create
 +      └─ vpcmod:tf:aws_route_table_association  module.test-vpc.aws_route_table_association.private[1]  create

Resources:
 + 21 to create

The infrastructure deploys successfully, and the Terraform state is automatically stored securely in Pulumi Cloud with full secret encryption support.

Migration Made Simple

For teams starting with existing Terraform code, the migration process is straightforward. Simply annotate your modules with a special comment:

// @pulumi-terraform-module vpcmod
module "my-vpc" {
  source             = "terraform-aws-modules/vpc/aws"
  version            = "6.0.1"
  azs                = ["us-west-2a", "us-west-2b"]
  name               = "test-vpc-123"
  public_subnets     = ["10.0.1.0/24", "10.0.2.0/24"]
  private_subnets    = ["10.0.3.0/24", "10.0.4.0/24"]
  enable_nat_gateway = true
  single_nat_gateway = true
}

Then run the conversion:

pulumi convert --from terraform --language typescript --out my-pulumi-project

The resulting project is ready to deploy with full Pulumi functionality.

Configuration Management

One of the key benefits is seamless configuration management. Instead of maintaining separate configurations for Pulumi and Terraform providers, you can reuse your existing Pulumi provider configuration:

const awsProvider = new aws.Provider("awsprovider", {
    region: "us-east-1",
    // more configuration
});

// Pass the AWS configuration to your VPC module provider
const vpcmodProvider = new vpcmod.Provider("vpcprovider", {
    "aws": awsProvider.terraformConfig().result
});

// Use the VPC module provider in your Module
const vpc = new vpcmod.Module("test-vpc", {...},
    {provider: vpcmodProvider}
);

This demonstrates how Terraform modules integrate seamlessly with existing Pulumi programs, allowing you to compose infrastructure components naturally.

What’s Supported

The integration provides comprehensive support for Pulumi’s core features:

  • Full Lifecycle Management: Preview, update, refresh, and destroy operations work exactly as expected
  • Resource Visibility: The entire resource tree is visible in Pulumi’s UI and CLI
  • Type Safety: Generated TypeScript interfaces provide IntelliSense and compile-time checking
  • Secret Management: First-class support for Pulumi’s secret encryption
  • Provider Configuration: Full control over Terraform provider settings

Current Limitations

As with any new technology integration, there are some current limitations to be aware of:

  • Transforms resource options are not supported
  • Targeted operations like pulumi up --target are not available
  • The protect resource option is not supported
  • Dependent resources may have limited support in some scenarios

Looking Ahead

This release represents a significant milestone in our journey to make infrastructure as code accessible to every developer. We’re already working on the next phase, which includes:

  • Enhanced state import capabilities for seamless Terraform-to-Pulumi migrations
  • Improved type inference for complex module schemas
  • Expanded support for additional Terraform features

The Path Forward

While this capability enables you to preserve your existing Terraform modules, we encourage teams to view this as a stepping stone rather than a final destination. The full benefits of modern infrastructure as code—including AI-assisted development, advanced testing capabilities, and seamless integration with modern development workflows—are best realized with native Pulumi components.

With AI developer tools making code conversion easier than ever, we’re committed to helping teams migrate their Terraform modules to native Pulumi when they’re ready. This capability ensures you can start your modernization journey today without being blocked by existing technical debt.

Get Started Today

The Terraform module support is available immediately. Install the latest Pulumi CLI and try it out with your existing Terraform modules. We’ve prepared comprehensive examples showcasing real-world scenarios, from simple VPC deployments to complex multi-module architectures.

If you encounter any issues or have suggestions for improvement, please open an issue or reach out in our Community Slack. Your feedback is invaluable as we continue to evolve this capability.

This release embodies our commitment to meeting developers where they are while providing a clear path forward to modern infrastructure practices. We’re excited to see how teams use this capability to accelerate their infrastructure modernization journey.