Ship
Infrastructure
Faster

Deliver infrastructure with high velocity and scale through software engineering.

Infrastructure as Code for Engineers

Every cloud, every language, every architecture, every engineer

Import joy into your cloud infrastructure

Write infrastructure code faster

Pulumi speeds up your inner dev loop for Infrastructure as Code (IaC) by allowing you to use an IDE giving you statement completion, real-time type checking, and interactive documentation out of the box. In addition you can leverage all of the capabilities of the programming language of your choice so you can reduce the total number of lines of code you’re writing.

Get started

Get started quickly with a project template that fits your use case.

import * as pulumi from "@pulumi/pulumi";
import * as awsx from "@pulumi/awsx";
import * as eks from "@pulumi/eks";

// Create a new VPC
const eksVpc = new awsx.ec2.Vpc("eks-vpc", {
    enableDnsHostnames: true,
    cidrBlock: "10.0.0.0/16",
});

// Create the EKS cluster
const eksCluster = new eks.Cluster("eks-cluster", {
    vpcId: eksVpc.vpcId,
    publicSubnetIds: eksVpc.publicSubnetIds,
    privateSubnetIds: eksVpc.privateSubnetIds,
    instanceType: "t2.medium",
    desiredCapacity: 3,
    minSize: 3,
    maxSize: 6,
    nodeAssociatePublicIpAddress: false,
});

// Export some values for use elsewhere
export const kubeconfig = eksCluster.kubeconfig;
export const vpcId = eksVpc.vpcId;
import pulumi
import pulumi_awsx as awsx
import pulumi_eks as eks

# Create a VPC for the EKS cluster
eks_vpc = awsx.ec2.Vpc("eks-vpc",
    enable_dns_hostnames=True,
    cidr_block="10.0.0.0/16")

# Create the EKS cluster
eks_cluster = eks.Cluster("eks-cluster",
    vpc_id=eks_vpc.vpc_id,
    public_subnet_ids=eks_vpc.public_subnet_ids,
    private_subnet_ids=eks_vpc.private_subnet_ids,
    instance_type="t2.medium",
    desired_capacity=3,
    min_size=3,
    max_size=6,
    node_associate_public_ip_address=False)

# Export values to use elsewhere
pulumi.export("kubeconfig", eks_cluster.kubeconfig)
pulumi.export("vpcId", eks_vpc.vpc_id)
package main

import (
  "github.com/pulumi/pulumi-awsx/sdk/go/awsx/ec2"
  "github.com/pulumi/pulumi-eks/sdk/go/eks"
  "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
  "github.com/pulumi/pulumi/sdk/v3/go/pulumi/config"
)

func main() {
  pulumi.Run(func(ctx *pulumi.Context) error {
    // Create a new VPC, subnets, and associated infrastructure
    vpcNetworkCidr := "10.0.0.0/16"
    eksVpc, err := ec2.NewVpc(ctx, "eks-vpc", &ec2.VpcArgs{
      EnableDnsHostnames: pulumi.Bool(true),
      CidrBlock:          &vpcNetworkCidr,
    })
    if err != nil {
      return err
    }

    // Create a new EKS cluster
    eksCluster, err := eks.NewCluster(ctx, "eks-cluster", &eks.ClusterArgs{
      VpcId:                        eksVpc.VpcId,
      PublicSubnetIds:              eksVpc.PublicSubnetIds,
      PrivateSubnetIds:             eksVpc.PrivateSubnetIds,
      InstanceType:                 pulumi.String("t2.medium"),
      DesiredCapacity:              pulumi.Int(3),
      MinSize:                      pulumi.Int(3),
      MaxSize:                      pulumi.Int(6),
      NodeAssociatePublicIpAddress: pulumi.Bool(false),
    })
    if err != nil {
      return err
    }

    // Export some values in case they are needed elsewhere
    ctx.Export("kubeconfig", eksCluster.Kubeconfig)
    ctx.Export("vpcId", eksVpc.VpcId)
    return nil
  })
}
using Pulumi;
using Awsx = Pulumi.Awsx;
using Eks = Pulumi.Eks;
using System.Collections.Generic;

return await Deployment.RunAsync(() =>
{
    // Create a new VPC
    var eksVpc = new Awsx.Ec2.Vpc("eks-vpc", new()
    {
        EnableDnsHostnames = true,
        CidrBlock = "10.0.0.0/16",
    });

    // Create the EKS cluster
    var eksCluster = new Eks.Cluster("eks-cluster", new()
    {
        VpcId = eksVpc.VpcId,
        PublicSubnetIds = eksVpc.PublicSubnetIds,
        PrivateSubnetIds = eksVpc.PrivateSubnetIds,
        InstanceType = "t2.medium",
        DesiredCapacity = 3,
        MinSize = 3,
        MaxSize = 6,
        NodeAssociatePublicIpAddress = false,
    });

    // Export some values for use elsewhere
    return new Dictionary<string, object?>
    {
        ["kubeconfig"] = eksCluster.Kubeconfig,
        ["vpcId"] = eksVpc.VpcId,
    };
});
package my_eks_cluster;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.awsx.ec2.Vpc;
import com.pulumi.awsx.ec2.VpcArgs;
import com.pulumi.eks.Cluster;
import com.pulumi.eks.ClusterArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var eksVpc = new Vpc("eksVpc", VpcArgs.builder()
            .enableDnsHostnames(true)
            .cidrBlock("10.0.0.0/16")
            .build());

        var eksCluster = new Cluster("eksCluster", ClusterArgs.builder()
            .vpcId(eksVpc.vpcId())
            .publicSubnetIds(eksVpc.publicSubnetIds())
            .privateSubnetIds(eksVpc.privateSubnetIds())
            .instanceType("t2.medium")
            .desiredCapacity(3)
            .minSize(3)
            .maxSize(6)
            .nodeAssociatePublicIpAddress(false)
            .build());

        ctx.export("kubeconfig", eksCluster.kubeconfig());
        ctx.export("vpcId", eksVpc.vpcId());
    }
}
name: pulumi-eks
description: A simple EKS cluster
runtime: yaml
resources:
  # Create a VPC for the EKS cluster
  eks-vpc:
    type: awsx:ec2:Vpc
    properties:
      enableDnsHostnames: true
      cidrBlock: "10.0.0.0/16"
  # Create the EKS cluster
  eks-cluster:
    type: eks:Cluster
    properties:
      vpcId: ${eks-vpc.vpcId}
      publicSubnetIds: ${eks-vpc.publicSubnetIds}
      privateSubnetIds: ${eks-vpc.privateSubnetIds}
      instanceType: "t2.medium"
      desiredCapacity: 3
      minSize: 3
      maxSize: 6
      nodeAssociatePublicIpAddress: false
outputs:
  # Output the Kubeconfig for the cluster
  kubeconfig: ${eks-cluster.kubeconfig}
  vpcId: ${eks-vpc.vpcId}

Leading engineering organizations are building with Pulumi

Mercedes-Benz Research and Development North America
Pulumi Pipeline

Ship applications faster

Pulumi speeds up your outer dev loop by making CI/CD for your IaC seamless and the default experience. Pulumi has integrations with all the popular CI/CD platforms and testing frameworks, so you can validate every change with testing and built-in policies. You can also build Pulumi Packages to create best-practice abstractions available in all languages.

Deliver ideas faster

Pulumi gives you a faster dev loop across the entire organization by guaranteeing the infrastructure software supply chain. Standard software packaging allows sharing and reuse of code across the organization along with org-wide policy enforcements, full change visibility and auditing across your entire organization, and automatic encryption for secrets and state. Pulumi provides the industry’s only automation workflow capability that allows software engineering to be applied to solve and manage cloud infrastructure at scale.

Get started

Get started quickly with a project template that fits your use case.

Pulumi Service

Do more with less

Use Pulumi's Automation API to create tooling that helps you and your engineers manage 10x the amount of resources versus traditional tooling.

What if IaC was a library and not just a CLI? Pulumi Automation API is the industry's first and only fully programmable infrastructure as code technology.

With Automation API, you can embed Pulumi right into your application code to drive complex deployment workflows programmatically. Build command-line tools, desktop applications, self-service infrastructure portals, and more, all in your language of choice — without having to "shell out" to another CLI. CLI tool to behind a HTTP API to a custom PaaS.

Automation API enables you and your company to scale 10x the amount of infrastructure managed per engineer.

Examples

  • import * as express from "express";
    import * as aws from "@pulumi/aws";
    import * as auto from "@pulumi/pulumi/automation";
    
    const app = express();
    
    app.post("/update", async (req, res) => {
    
        // Create a new stack.
        const stack = await auto.createStack({
            stackName: req.body.stackName,
            projectName: req.body.projectName,
            program: () => {
                return {
                    bucket: new aws.s3.Bucket("my-bucket");
                };
            },
        });
    
        // Update the stack.
        await stack.up({ onOutput: console.info });
        return res.send("Update complete.");
    });
    
    app.listen(3000);
    
  • import (
        "fmt"
    
        "github.com/pulumi/pulumi/sdk/v3/go/auto"
        "github.com/pulumi/pulumi/sdk/v3/go/auto/optup"
        "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
        "github.com/ThorstenHans/stringer/pkg/stringer"
        "github.com/spf13/cobra"
    )
    
    func pulumiProgram(ctx *pulumi.Context) error {
        // Your Pulumi program.
    }
    
    var deployCmd = &cobra.Command{
        Use:   "deploy",
        Short:  "Deploy my infrastructure.",
        Run: func(cmd *cobra.Command, args []string) error {
            ctx := context.Background()
            projectName := "example"
            stackName := "dev"
            s, err := auto.UpsertStackInlineSource(ctx, stackName, projectName, pulumiProgram)
            if err != nil {
              return err
            }
    
            w := s.Workspace()
    
            // for inline source programs, we must manage plugins ourselves
            err = w.InstallPlugin(ctx, "aws", "v4.0.0")
            if err != nil {
              fmt.Printf("Failed to install program plugins: %v\n", err)
              os.Exit(1)
            }
    
            // set stack configuration specifying the AWS region to deploy
            s.SetConfig(ctx, "aws:region", auto.ConfigValue{Value: "us-west-2"})
    
            _, err = s.Refresh(ctx)
            if err != nil {
              return err
            }
    
            stdoutStreamer := optup.ProgressStreams(os.Stdout)
    
            res, err := s.Up(ctx, stdoutStreamer)
            if err != nil {
              return err
            }
    
            return nil
        },
    }
    
    func init() {
        rootCmd.AddCommand(deployCmd)
    }
    
  • import sys
    import json
    import pulumi
    import pulumi_aws as aws
    from pulumi import automation as auto
    from mysql.connector import connect
    
    
    # This is our pulumi program in "inline function" form
    def pulumi_program():
        default_vpc = aws.ec2.get_vpc(default=True)
        public_subnet_ids = aws.ec2.get_subnet_ids(vpc_id=default_vpc.id)
        subnet_group = aws.rds.SubnetGroup("db_subnet", subnet_ids=public_subnet_ids.ids)
    
        # make a public security group for our cluster for the migration
        security_group = aws.ec2.SecurityGroup("public_group",
                                              ingress=[aws.ec2.SecurityGroupIngressArgs(
                                                  protocol="-1",
                                                  from_port=0,
                                                  to_port=0,
                                                  cidr_blocks=["0.0.0.0/0"]
                                              )],
                                              egress=[aws.ec2.SecurityGroupEgressArgs(
                                                  protocol="-1",
                                                  from_port=0,
                                                  to_port=0,
                                                  cidr_blocks=["0.0.0.0/0"]
                                              )])
    
        # example on, you should change this
        db_name = "hellosql"
        db_user = "hellosql"
        db_pass = "hellosql"
    
        # provision our db
        cluster = aws.rds.Cluster("db",
                                  engine=aws.rds.EngineType.AURORA_MYSQL,
                                  engine_version="5.7.mysql_aurora.2.10.2",
                                  database_name=db_name,
                                  master_username=db_user,
                                  master_password=db_pass,
                                  skip_final_snapshot=True,
                                  db_subnet_group_name=subnet_group.name,
                                  vpc_security_group_ids=[security_group.id])
    
        cluster_instance = aws.rds.ClusterInstance("db_instance",
                                                  cluster_identifier=cluster.cluster_identifier,
                                                  instance_class=aws.rds.InstanceType.T3_SMALL,
                                                  engine=aws.rds.EngineType.AURORA_MYSQL,
                                                  engine_version="5.7.mysql_aurora.2.10.2",
                                                  publicly_accessible=True,
                                                  db_subnet_group_name=subnet_group.name)
    
        pulumi.export("host", cluster.endpoint)
        pulumi.export("db_name", db_name)
        pulumi.export("db_user", db_user)
        pulumi.export("db_pass", db_pass)
    
    
    # To destroy our program, we can run python main.py destroy
    destroy = False
    args = sys.argv[1:]
    if len(args) > 0:
        if args[0] == "destroy":
            destroy = True
    
    project_name = "database_migration"
    stack_name = "dev"
    
    # create (or select if one already exists) a stack that uses our inline program
    stack = auto.create_or_select_stack(stack_name=stack_name,
                                        project_name=project_name,
                                        program=pulumi_program)
    
    print("successfully initialized stack")
    
    # for inline programs, we must manage plugins ourselves
    print("installing plugins...")
    stack.workspace.install_plugin("aws", "v4.0.0")
    print("plugins installed")
    
    # set stack configuration specifying the AWS region to deploy
    print("setting up config")
    stack.set_config("aws:region", auto.ConfigValue(value="us-west-2"))
    print("config set")
    
    print("refreshing stack...")
    stack.refresh(on_output=print)
    print("refresh complete")
    
    if destroy:
        print("destroying stack...")
        stack.destroy(on_output=print)
        print("stack destroy complete")
        sys.exit()
    
    print("updating stack...")
    up_res = stack.up(on_output=print)
    print(f"update summary: \n{json.dumps(up_res.summary.resource_changes, indent=4)}")
    print(f"db host url: {up_res.outputs['host'].value}")
    
    print("configuring db...")
    with connect(
            host=up_res.outputs['host'].value,
            user=up_res.outputs['db_user'].value,
            password=up_res.outputs['db_pass'].value,
            database=up_res.outputs['db_name'].value) as connection:
        print("db configured!")
    
        # make sure the table exists
        print("creating table...")
        create_table_query = """CREATE TABLE IF NOT EXISTS hello_pulumi(
            id int(9) NOT NULL PRIMARY KEY,
            color varchar(14) NOT NULL);
            """
        with connection.cursor() as cursor:
            cursor.execute(create_table_query)
            connection.commit()
    
        # seed the table with some data to start
        seed_table_query = """INSERT IGNORE INTO hello_pulumi (id, color)
        VALUES
            (1, 'Purple'),
            (2, 'Violet'),
            (3, 'Plum');
        """
        with connection.cursor() as cursor:
            cursor.execute(seed_table_query)
            connection.commit()
    
        print("rows inserted!")
        print("querying to verify data...")
    
        # read the data back
        read_table_query = """SELECT COUNT(*) FROM hello_pulumi;"""
        with connection.cursor() as cursor:
            cursor.execute(read_table_query)
            result = cursor.fetchone()
            print(f"Result: {json.dumps(result)}")
    
        print("database, table and rows successfully configured")
    

Atlassian reduced time spent on maintenance by 50%

"Using Pulumi and Python, our team quickly and easily built a repeatable pipeline that deploys development environments for more than 100 team members worldwide. The benefits of working in languages we know can’t be overstated. That just made moving to the Pulumi Cloud Engineering Platform an obvious choice for the team."

- Mike Corsaro, Senior Software Engineer at Bitbucket

Get started today

Pulumi is open source and free to get started. Deploy your first stack today.

@PulumiCorp is pretty awesome. Just nuked a couple of load balancers and recreated them, no big deal.

@joepferguson@phpc.social

Twitter

All in all, I''m very happy with making the transition to Pulumi! I became way more productive managing my infrastructure. At the same time I ended up enjoying the work of doing so a lot more - which is really important too. (click to read blog post)

Erik Näslund

Twitter

With @PulumiCorp I said goodbye to #YAML and JSON supersets. I went back to what I love: #code. Code. End to end. Functional, even. #Kubernetes is pleasant again.

matticala

Twitter

There is no way around the fact that devops is complicated but @PulumiCorp is a game changer for me. Blows away CloudForamtion, TerraForm, CDK, etc.

@BryanMigliorisi

Twitter

I'd like to congratulate @PulumiCorp on an AWESOME CLI experience... it's just beautiful

MartinDotNet

Twitter

Having used Pulumi the last 2 years after switching from Terraform I want to share some of my experience by comparing both infrastructure as code tools and explain why I prefer Pulumi in most situations. In general, I have successfully provisioned infrastructure with both tools, but from my experience Pulumi makes it easier for me. (click to read blog post)

Matthias Müller

Twitter

I'm actually learning more about TS/JS with Pulumi. It really has been a joy to use. Kudos to the team for making such an awesome tool!

monde_

Twitter

Pulumi is better than Terraform. Hands down. It has all the features of Terraform, but written with the simplicity and power of a fully featured programming language.

Christopher Lenard

Twitter

I just spent a few hours getting used to @PulumiCorp SDK and I am already asking myself why I ever used #Terraform 😂 Real Infrastructure as Code all the way 💪 😍

JanDamaschke

Twitter

First, run of my new #dev environment. Love how easy it is with @PulumiCorp ❤️ 🚀 #InfrastructureAsCode

eliostruyf

Twitter

Ok, Pulumi just got even more real. With “pulumi convert” and CrossCode support in YAML, it just overtook HCL and Terraform in position #1 for me. Sorry HashiCorp Pulumi is now in the lead.

Eric Hendrickson, CTO Provisions Group

Twitter

Continuing on my thread about @PulumiCorp from a while ago: holy **** I am a convert. I needed to setup a staging environment that was mostly identical to prod, and once I trued up our Pulumi stack with AWS, it took minutes to do this. How have I lived without this until now?

@krangarajan

Twitter

Just Pulumi-ified a ton of random AWS resources & it feels so good.

BrandonBloom

Twitter

From PoC in a week, to reaching production with confidence the week after, we’re super impressed by Pulumi’s focus on the developer experience and general ease of use. We have since expanded our usage of Pulumi to manage our infrastructure and have a GitHub Actions-powered workflow with automatic PR previews that is a breeze to use. (click to read blog post)

Tiago Sousa

Twitter

I've been playing around with Pulumi a bit and I have to say this is really quite well done. The documentation is very polished and all tutorials I tried worked exactly copy paste out of the box.

sheeshee

Twitter

#Pulumi is the fast growing new kit on the block. Great convo with @PulumiCorp at what the (near) future holds in terms of platform capabilities. Very exciting. #cloudengineering #devops #gitops @ema_research

TorstenVolk

Twitter

I just want to say that I''m amazed at what Pulumi can provide. I make twitch videos of my side projects and I was playing with Pulumi in creating my lambda function. I wanted to use my Pulumi code to...

u/akali1987

Twitter

Save yourselves from the yaml, use pulumi

Frassle

Twitter

Without a doubt the most approachable tool in the IaaC space is @PulumiCorp . Somewhat enjoying provisioning a scheduled run of a Lambda.

@Vetium

Twitter

Why is @PulumiCorp so good, absolute minimum you can replicate everything you can do with other tools but that's just the start. If your #IaC is proper code you can use other sdks to fill gaps and it can be seamless. Used sdk to get secrets to pass to Pulumi, just worked 😍

@ShahidDev

Twitter

The developer experience of Pulumi is just sublime. As a prior Terraform user, the grass is substantially greener on this side. I''m so glad I made the switch two years back. Using Terraform for my current use case would be a massive downgrade.

@justedagain

Twitter

Congratulations Joe. Loved the idea of pulumi since I did a talk with one of the first releases. I genuinely think this model is the future inside DevOps and out

ItemLevel1

Twitter

Give Pulumi a shot and you will never look back @PulumiCorp

hossambarakat_

Twitter

Been using Pulumi to write C# IaC for a while now, very much prefer it to HCL.

samcogan

Twitter

Pulumi ❤️❤️❤️❤️

omerlh

Twitter