Import Terraform Modules
Leverage the module ecosystem
Pulumi can directly use existing Terraform modules from the Terraform Registry, private registries, or local sources. This allows you to access thousands of existing modules without rewriting them in Pulumi.
Add Terraform modules
Use the pulumi package add
command to add Terraform modules to your project:
# Add a module from the Terraform Registry $ pulumi package add terraform-module terraform-aws-modules/vpc/aws 6.0.0 vpc # Add a local module $ pulumi package add terraform-module ./path/to/module localmod
Example: AWS VPC module
Let’s use the popular AWS vpc
module to create a VPC with subnets, and then deploy an EC2 instance in that VPC:
First, create a new Pulumi program:
$ mkdir pulumi-terraform-modules-test && cd pulumi-terraform-modules-test $ pulumi new aws-typescript --yes
Next, add the VPC module:
$ pulumi package add terraform-module terraform-aws-modules/vpc/aws 6.0.0 vpc
Then use it in your Pulumi program:
import * as pulumi from "@pulumi/pulumi"; import * as aws from "@pulumi/aws"; import * as vpc from "@pulumi/vpc"; // Use the Terraform VPC module const myVpc = new vpc.Module("my-vpc", { name: "my-vpc", cidr: "10.0.0.0/16", azs: ["us-west-2a", "us-west-2b", "us-west-2c"], public_subnets: ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"], private_subnets: ["10.0.10.0/24", "10.0.11.0/24", "10.0.12.0/24"], enable_nat_gateway: true, enable_vpn_gateway: true, tags: { Terraform: "true", Environment: "dev", }, }); // Create a security group const webSg = new aws.ec2.SecurityGroup("web-sg", { name: "web-sg", description: "Security group for web servers", vpcId: myVpc.vpc_id.apply(id => id!), ingress: [ { description: "HTTP", fromPort: 80, toPort: 80, protocol: "tcp", cidrBlocks: ["0.0.0.0/0"], }, { description: "SSH", fromPort: 22, toPort: 22, protocol: "tcp", cidrBlocks: ["0.0.0.0/0"], }, ], egress: [ { fromPort: 0, toPort: 0, protocol: "-1", cidrBlocks: ["0.0.0.0/0"], }, ], }); // Get the latest Amazon Linux 2 AMI const amazonLinux = aws.ec2.getAmiOutput({ mostRecent: true, owners: ["amazon"], filters: [ { name: "name", values: ["amzn2-ami-hvm-*-x86_64-gp2"], }, ], }); // Create an EC2 instance in the VPC const webServer = new aws.ec2.Instance("web-server", { ami: amazonLinux.id, instanceType: "t3.micro", subnetId: myVpc.public_subnets.apply(subnets => subnets![0]), vpcSecurityGroupIds: [webSg.id], associatePublicIpAddress: true, userData: `#!/bin/bash yum update -y yum install -y httpd systemctl start httpd systemctl enable httpd echo "<h1>Hello from Pulumi and Terraform modules!</h1>" > /var/www/html/index.html `, tags: { Name: "web-server", Environment: "dev", }, }); // Output important information export const vpcId = myVpc.vpc_id; export const instanceId = webServer.id; export const publicIp = webServer.publicIp; export const websiteUrl = pulumi.interpolate`http://${webServer.publicIp}`;
First, create a new Pulumi program:
$ mkdir pulumi-terraform-modules-test && cd pulumi-terraform-modules-test $ pulumi new aws-python --yes
Next, add the VPC module:
$ pulumi package add terraform-module terraform-aws-modules/vpc/aws 6.0.0 vpc
Then use it in your Pulumi program:
import pulumi import pulumi_aws as aws import pulumi_vpc as vpc # Use the Terraform VPC module my_vpc = vpc.Module("my-vpc", name="my-vpc", cidr="10.0.0.0/16", azs=["us-west-2a", "us-west-2b", "us-west-2c"], public_subnets=["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"], private_subnets=["10.0.10.0/24", "10.0.11.0/24", "10.0.12.0/24"], enable_nat_gateway=True, enable_vpn_gateway=True, tags={ "Terraform": "true", "Environment": "dev", } ) # Create a security group web_sg = aws.ec2.SecurityGroup("web-sg", name="web-sg", description="Security group for web servers", vpc_id=my_vpc.vpc_id.apply(lambda id: id), ingress=[ { "description": "HTTP", "from_port": 80, "to_port": 80, "protocol": "tcp", "cidr_blocks": ["0.0.0.0/0"], }, { "description": "SSH", "from_port": 22, "to_port": 22, "protocol": "tcp", "cidr_blocks": ["0.0.0.0/0"], }, ], egress=[ { "from_port": 0, "to_port": 0, "protocol": "-1", "cidr_blocks": ["0.0.0.0/0"], } ] ) # Get the latest Amazon Linux 2 AMI amazon_linux = aws.ec2.get_ami( most_recent=True, owners=["amazon"], filters=[ { "name": "name", "values": ["amzn2-ami-hvm-*-x86_64-gp2"], } ] ) # Create an EC2 instance in the VPC web_server = aws.ec2.Instance("web-server", ami=amazon_linux.id, instance_type="t3.micro", subnet_id=my_vpc.public_subnets.apply(lambda subnets: subnets[0]), vpc_security_group_ids=[web_sg.id], associate_public_ip_address=True, user_data="""#!/bin/bash yum update -y yum install -y httpd systemctl start httpd systemctl enable httpd echo "<h1>Hello from Pulumi and Terraform modules!</h1>" > /var/www/html/index.html """, tags={ "Name": "web-server", "Environment": "dev", } ) # Output important information pulumi.export("vpcId", my_vpc.vpc_id) pulumi.export("instanceId", web_server.id) pulumi.export("publicIp", web_server.public_ip) pulumi.export("websiteUrl", pulumi.Output.format("http://{0}", web_server.public_ip))
First, create a new Pulumi program:
$ mkdir pulumi-terraform-modules-test && cd pulumi-terraform-modules-test $ pulumi new aws-go --yes
Next, add the VPC module:
$ pulumi package add terraform-module terraform-aws-modules/vpc/aws 6.0.0 vpc
Then use it in your Pulumi program:
package main import ( "github.com/pulumi/pulumi-aws/sdk/v6/go/aws/ec2" vpc "github.com/pulumi/pulumi-terraform-module/sdks/go/vpc/v6/vpc" "github.com/pulumi/pulumi/sdk/v3/go/pulumi" ) func main() { pulumi.Run(func(ctx *pulumi.Context) error { // Use the Terraform VPC module myVpc, err := vpc.NewModule(ctx, "my-vpc", &vpc.ModuleArgs{ Name: pulumi.String("my-vpc"), Cidr: pulumi.String("10.0.0.0/16"), Azs: pulumi.StringArray{pulumi.String("us-west-2a"), pulumi.String("us-west-2b"), pulumi.String("us-west-2c")}, Private_subnets: pulumi.StringArray{pulumi.String("10.0.1.0/24"), pulumi.String("10.0.2.0/24"), pulumi.String("10.0.3.0/24")}, Public_subnets: pulumi.StringArray{pulumi.String("10.0.10.0/24"), pulumi.String("10.0.11.0/24"), pulumi.String("10.0.12.0/24")}, Enable_nat_gateway: pulumi.Bool(true), Enable_vpn_gateway: pulumi.Bool(true), Tags: pulumi.StringMap{ "Terraform": pulumi.String("true"), "Environment": pulumi.String("dev"), }, }) if err != nil { return err } // Get the latest Amazon Linux 2 AMI amazonLinux, err := ec2.LookupAmi(ctx, &ec2.LookupAmiArgs{ MostRecent: pulumi.BoolRef(true), Owners: []string{"amazon"}, Filters: []ec2.GetAmiFilter{ { Name: "name", Values: []string{"amzn2-ami-hvm-*-x86_64-gp2"}, }, }, }) if err != nil { return err } // Create a security group webSg, err := ec2.NewSecurityGroup(ctx, "web-sg", &ec2.SecurityGroupArgs{ Name: pulumi.String("web-sg"), Description: pulumi.String("Security group for web servers"), VpcId: myVpc.Vpc_id, Ingress: ec2.SecurityGroupIngressArray{ &ec2.SecurityGroupIngressArgs{ Description: pulumi.String("HTTP"), FromPort: pulumi.Int(80), ToPort: pulumi.Int(80), Protocol: pulumi.String("tcp"), CidrBlocks: pulumi.StringArray{pulumi.String("0.0.0.0/0")}, }, &ec2.SecurityGroupIngressArgs{ Description: pulumi.String("SSH"), FromPort: pulumi.Int(22), ToPort: pulumi.Int(22), Protocol: pulumi.String("tcp"), CidrBlocks: pulumi.StringArray{pulumi.String("0.0.0.0/0")}, }, }, Egress: ec2.SecurityGroupEgressArray{ &ec2.SecurityGroupEgressArgs{ FromPort: pulumi.Int(0), ToPort: pulumi.Int(0), Protocol: pulumi.String("-1"), CidrBlocks: pulumi.StringArray{pulumi.String("0.0.0.0/0")}, }, }, }) if err != nil { return err } // Create an EC2 instance in the VPC webServer, err := ec2.NewInstance(ctx, "web-server", &ec2.InstanceArgs{ Ami: pulumi.String(amazonLinux.Id), InstanceType: pulumi.String("t3.micro"), SubnetId: myVpc.Public_subnets.ApplyT(func(subnets []string) string { return subnets[0] }).(pulumi.StringOutput), VpcSecurityGroupIds: pulumi.StringArray{webSg.ID()}, AssociatePublicIpAddress: pulumi.Bool(true), UserData: pulumi.String(`#!/bin/bash yum update -y yum install -y httpd systemctl start httpd systemctl enable httpd echo "<h1>Hello from Pulumi and Terraform modules!</h1>" > /var/www/html/index.html `), Tags: pulumi.StringMap{ "Name": pulumi.String("web-server"), "Environment": pulumi.String("dev"), }, }) if err != nil { return err } // Output important information ctx.Export("vpcId", myVpc.Vpc_id) ctx.Export("instanceId", webServer.ID()) ctx.Export("publicIp", webServer.PublicIp) ctx.Export("websiteUrl", pulumi.Sprintf("http://%s", webServer.PublicIp)) return nil }) }
First, create a new Pulumi program:
$ mkdir pulumi-terraform-modules-test && cd pulumi-terraform-modules-test $ pulumi new aws-csharp --yes
Next, add the VPC module:
$ pulumi package add terraform-module terraform-aws-modules/vpc/aws 6.0.0 vpc
The pulumi package add ...
command will add the required dependencies to the solution file, but you’ll need to manually add the following directive:
<PropertyGroup> <!-- ... --> <DefaultItemExcludes>$(DefaultItemExcludes);sdks/**/*.cs</DefaultItemExcludes> </PropertyGroup>
Then use it in your Pulumi program:
using System.Collections.Generic; using Pulumi; using Pulumi.Aws.Ec2; using Pulumi.Vpc; return await Deployment.RunAsync(() => { // Use the Terraform VPC module var myVpc = new Vpc("my-vpc", new VpcArgs { Name = "my-vpc", Cidr = "10.0.0.0/16", Azs = new[] { "us-west-2a", "us-west-2b", "us-west-2c" }, PrivateSubnets = new[] { "10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24" }, PublicSubnets = new[] { "10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24" }, EnableNatGateway = true, EnableVpnGateway = true, Tags = new Dictionary<string, string> { ["Terraform"] = "true", ["Environment"] = "dev", }, }); // Get the latest Amazon Linux 2 AMI var amazonLinux = GetAmi.Invoke(new GetAmiInvokeArgs { MostRecent = true, Owners = new[] { "amazon" }, Filters = new[] { new GetAmiFilterInputArgs { Name = "name", Values = new[] { "amzn2-ami-hvm-*-x86_64-gp2" }, }, }, }); // Create a security group var webSg = new SecurityGroup("web-sg", new SecurityGroupArgs { Name = "web-sg", Description = "Security group for web servers", VpcId = myVpc.VpcId, Ingress = new[] { new SecurityGroupIngressArgs { Description = "HTTP", FromPort = 80, ToPort = 80, Protocol = "tcp", CidrBlocks = new[] { "0.0.0.0/0" }, }, new SecurityGroupIngressArgs { Description = "SSH", FromPort = 22, ToPort = 22, Protocol = "tcp", CidrBlocks = new[] { "0.0.0.0/0" }, }, }, Egress = new[] { new SecurityGroupEgressArgs { FromPort = 0, ToPort = 0, Protocol = "-1", CidrBlocks = new[] { "0.0.0.0/0" }, }, }, }); // Create an EC2 instance in the VPC var webServer = new Instance("web-server", new InstanceArgs { Ami = amazonLinux.Apply(ami => ami.Id), InstanceType = "t3.micro", SubnetId = myVpc.PublicSubnets.Apply(subnets => subnets[0]), VpcSecurityGroupIds = new[] { webSg.Id }, AssociatePublicIpAddress = true, UserData = @"#!/bin/bash yum update -y yum install -y httpd systemctl start httpd systemctl enable httpd echo ""<h1>Hello from Pulumi and Terraform modules!</h1>"" > /var/www/html/index.html ", Tags = new Dictionary<string, string> { ["Name"] = "web-server", ["Environment"] = "dev", }, }); return new Dictionary<string, object?> { ["vpcId"] = myVpc.VpcId, ["publicSubnets"] = myVpc.PublicSubnets, ["privateSubnets"] = myVpc.PrivateSubnets, ["instanceId"] = webServer.Id, ["publicIp"] = webServer.PublicIp, ["websiteUrl"] = webServer.PublicIp.Apply(ip => $"http://{ip}"), }; });
First, create a new Pulumi program:
$ mkdir pulumi-terraform-modules-test && cd pulumi-terraform-modules-test $ pulumi new aws-java --yes
Next, add the VPC module:
$ pulumi package add terraform-module terraform-aws-modules/vpc/aws 6.0.0 vpc
The pulumi package add ...
command will output some important instructions. There are two steps you must perform manually: copy the contents of the generated SDK to your Java project, and add the dependencies to pom.xml
:
<dependencies> <!-- ... --> <dependency> <groupId>com.google.code.findbugs</groupId> <artifactId>jsr305</artifactId> <version>3.0.2</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.9</version> </dependency> </dependencies>
Then use it in your Pulumi program, by replacing the contents of src/main/java/myproject/App.java
with:
package myproject; import com.pulumi.Pulumi; import com.pulumi.aws.ec2.Ec2Functions; import com.pulumi.aws.ec2.Instance; import com.pulumi.aws.ec2.InstanceArgs; import com.pulumi.aws.ec2.SecurityGroup; import com.pulumi.aws.ec2.SecurityGroupArgs; import com.pulumi.aws.ec2.inputs.GetAmiArgs; import com.pulumi.aws.ec2.inputs.GetAmiFilterArgs; import com.pulumi.aws.ec2.inputs.SecurityGroupEgressArgs; import com.pulumi.aws.ec2.inputs.SecurityGroupIngressArgs; import java.util.Collections; import java.util.Map; public class App { public static void main(String[] args) { Pulumi.run(ctx -> { // Use the Terraform VPC module var myVpc = new com.pulumi.vpc.Module("my-vpc", com.pulumi.vpc.ModuleArgs.builder() .name("my-vpc") .cidr("10.0.0.0/16") .azs("us-west-2a", "us-west-2b", "us-west-2c") .private_subnets("10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24") .public_subnets("10.0.10.0/24", "10.0.11.0/24", "10.0.12.0/24") .enable_nat_gateway(true) .enable_vpn_gateway(true) .tags(Map.of( "Terraform", "true", "Environment", "dev" )) .build()); // Get the latest Amazon Linux 2 AMI var amazonLinux = Ec2Functions.getAmi(GetAmiArgs.builder() .mostRecent(true) .owners("amazon") .filters(GetAmiFilterArgs.builder() .name("name") .values("amzn2-ami-hvm-*-x86_64-gp2") .build()) .build()); // Create a security group var webSg = new SecurityGroup("web-sg", SecurityGroupArgs.builder() .name("web-sg") .description("Security group for web servers") .vpcId(myVpc.vpc_id().applyValue(id->id.get()).applyValue(String::valueOf)) .ingress( SecurityGroupIngressArgs.builder() .description("HTTP") .fromPort(80) .toPort(80) .protocol("tcp") .cidrBlocks("0.0.0.0/0") .build(), SecurityGroupIngressArgs.builder() .description("SSH") .fromPort(22) .toPort(22) .protocol("tcp") .cidrBlocks("0.0.0.0/0") .build() ) .egress(SecurityGroupEgressArgs.builder() .fromPort(0) .toPort(0) .protocol("-1") .cidrBlocks("0.0.0.0/0") .build()) .build()); // Output<List<String>> secGrps = webSg.id().applyValue(s -> Collections.singletonList(s)); // Create an EC2 instance in the VPC var webServer = new Instance("web-server", InstanceArgs.builder() .ami(amazonLinux.applyValue(ami -> ami.id())) .instanceType("t3.micro") .subnetId(myVpc.public_subnets().applyValue(subnets -> subnets.get().get(0))) .vpcSecurityGroupIds(webSg.id().applyValue(s -> Collections.singletonList(s))) .associatePublicIpAddress(true) .userData(String.join("\n", "#!/bin/bash", "yum update -y", "yum install -y httpd", "systemctl start httpd", "systemctl enable httpd", "echo \"<h1>Hello from Pulumi and Terraform modules!</h1>\" > /var/www/html/index.html" )) .tags(Map.of( "Name", "web-server", "Environment", "dev" )) .build()); // Output important information ctx.export("vpcId", myVpc.vpc_id()); ctx.export("instanceId", webServer.id()); ctx.export("publicIp", webServer.publicIp()); ctx.export("websiteUrl", webServer.publicIp().applyValue(ip -> String.format("http://%s", ip))); }); } }
First, create a new Pulumi program:
$ mkdir pulumi-terraform-modules-test && cd pulumi-terraform-modules-test $ pulumi new aws-yaml --yes
Next, add the VPC module:
$ pulumi package add terraform-module terraform-aws-modules/vpc/aws 6.0.0 vpc
Then use it in your Pulumi program:
name: pulumi-terraform-modules-example runtime: yaml description: Use Terraform modules in Pulumi variables: # Get the latest Amazon Linux 2 AMI amazonLinux: fn::invoke: function: aws:ec2:getAmi arguments: mostRecent: true owners: ["amazon"] filters: - name: name values: ["amzn2-ami-hvm-*-x86_64-gp2"] resources: # Use the Terraform VPC module my-vpc: type: vpc:index:Module properties: name: my-vpc cidr: 10.0.0.0/16 azs: ["us-west-2a", "us-west-2b", "us-west-2c"] private_subnets: ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"] public_subnets: ["10.0.10.0/24", "10.0.11.0/24", "10.0.12.0/24"] enable_nat_gateway: true enable_vpn_gateway: true tags: Terraform: "true" Environment: "dev" # Create a security group web-sg: type: aws:ec2:SecurityGroup properties: name: web-sg description: Security group for web servers vpcId: ${my-vpc.vpc_id} ingress: - description: HTTP fromPort: 80 toPort: 80 protocol: tcp cidrBlocks: ["0.0.0.0/0"] - description: SSH fromPort: 22 toPort: 22 protocol: tcp cidrBlocks: ["0.0.0.0/0"] egress: - fromPort: 0 toPort: 0 protocol: "-1" cidrBlocks: ["0.0.0.0/0"] # Create an EC2 instance in the VPC web-server: type: aws:ec2:Instance properties: ami: ${amazonLinux.id} instanceType: t3.micro subnetId: ${my-vpc.public_subnets[0]} vpcSecurityGroupIds: - ${web-sg.id} associatePublicIpAddress: true userData: | #!/bin/bash yum update -y yum install -y httpd systemctl start httpd systemctl enable httpd echo "<h1>Hello from Pulumi and Terraform modules!</h1>" > /var/www/html/index.html tags: Name: web-server Environment: dev outputs: vpcId: ${my-vpc.vpc_id} instanceId: ${web-server.id} publicIp: ${web-server.publicIp} websiteUrl: http://${web-server.publicIp} # The vpc Terraform module package definition packages: vpc: source: terraform-module version: 0.1.4 parameters: - terraform-aws-modules/vpc/aws - 6.0.0 - vpc
Compare with Terraform
The same functionality in Terraform would look like:
# Terraform equivalent module "vpc" { source = "terraform-aws-modules/vpc/aws" name = "my-vpc" cidr = "10.0.0.0/16" azs = ["us-west-2a", "us-west-2b", "us-west-2c"] private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"] public_subnets = ["10.0.10.0/24", "10.0.11.0/24", "10.0.12.0/24"] enable_nat_gateway = true enable_vpn_gateway = true tags = { Terraform = "true" Environment = "dev" } } data "aws_ami" "amazon_linux" { most_recent = true owners = ["amazon"] filter { name = "name" values = ["amzn2-ami-hvm-*-x86_64-gp2"] } } resource "aws_security_group" "web_sg" { name = "web-sg" description = "Security group for web servers" vpc_id = module.vpc.vpc_id ingress { description = "HTTP" from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } ingress { description = "SSH" from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } } resource "aws_instance" "web_server" { ami = data.aws_ami.amazon_linux.id instance_type = "t3.micro" subnet_id = module.vpc.public_subnets[0] vpc_security_group_ids = [aws_security_group.web_sg.id] associate_public_ip_address = true user_data = <<-EOF #!/bin/bash yum update -y yum install -y httpd systemctl start httpd systemctl enable httpd echo "<h1>Hello from Pulumi and Terraform modules!</h1>" > /var/www/html/index.html EOF tags = { Name = "web-server" Environment = "dev" } } output "vpc_id" { value = module.vpc.vpc_id } output "instance_id" { value = aws_instance.web_server.id } output "public_ip" { value = aws_instance.web_server.public_ip } output "website_url" { value = "http://${aws_instance.web_server.public_ip}" }
Best practices
- Pin module versions: Always specify module versions in production
- Review module source: Understand what the module does before using it
- Test module outputs: Verify that module outputs work as expected
- Monitor module updates: Keep track of module updates and breaking changes
- Use reputable sources: Prefer well-maintained modules from trusted sources
- Document module usage: Document why you chose specific modules and their configuration
Clean up
Test your deployment and clean up resources:
# Deploy the stack $ pulumi up # Visit the website URL from the output # When done, destroy the resources $ pulumi destroy
Thank you for your feedback!
If you have a question about how to use Pulumi, reach out in Community Slack.
Open an issue on GitHub to report a problem or suggest an improvement.