Join us at the Cloud Engineering Summit on October 20th for a free day of learning. Save your spot.

Architecture & Concepts

Pulumi is a modern infrastructure as code platform. It leverages existing programming languages—TypeScript, JavaScript, Python, Go, and .NET—and their native ecosystem to interact with cloud resources through the Pulumi SDK. A downloadable CLI, runtime, libraries, and a hosted service work together to deliver a robust way of provisioning, updating, and managing cloud infrastructure.

If this is your first time using Pulumi, you likely want to begin with the Getting Started guide for your cloud of choice. It will walk you through an AWS, Azure, GCP, or Kubernetes deployment from start to finish.

Pulumi Overview

This diagram illustrates the structure and major components of Pulumi.

Pulumi programming model diagram.

Pulumi programs, written in general-purpose programming languages, describe how your cloud infrastructure should be composed. To declare new infrastructure in your program, you allocate resource objects whose properties correspond to the desired state of your infrastructure. These properties are also used between resources to handle any necessary dependencies and can be exported outside of the stack, if needed.

Programs reside in a project, which is a directory that contains source code for the program and metadata on how to run the program. After writing your program, you run the Pulumi CLI command pulumi up from within your project directory. This command creates an isolated and configurable instance of your program, known as a stack. Stacks are similar to different deployment environments that you use when testing and rolling out application updates. For instance, you can have distinct development, staging, and production stacks that you create and test against.

Example

To illustrate these concepts, the following program shows how to create an AWS EC2 security group named web-sg with a single ingress rule and a t2.micro-sized EC2 instance using that security group.

To use the security group, the EC2 resource requires the security group’s ID. Pulumi enables this through the output property name on the security group resource. Pulumi understands dependencies between resources and uses the relationships between resources to maximize parallelism and ensures correct ordering when a stack is instantiated.

Finally, the server’s resulting IP address and DNS name are exported as stack outputs so that their values can be accessed through either a CLI command or by another stack.

"user strict";
const pulumi = require("@pulumi/pulumi");
const aws = require("@pulumi/aws");

const group = new aws.ec2.SecurityGroup("web-sg", {
    description: "Enable HTTP access",
    ingress: [{ protocol: "tcp", fromPort: 80, toPort: 80, cidrBlocks: ["0.0.0.0/0"] }],
});

const server = new aws.ec2.Instance("web-server", {
    ami: "ami-6869aa05",
    instanceType: "t2.micro",
    vpcSecurityGroupIds: [ group.name ], // reference the security group resource above
});

export const publicIp = server.publicIp;
export const publicDns = server.publicDns;
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const group = new aws.ec2.SecurityGroup("web-sg", {
    description: "Enable HTTP access",
    ingress: [{ protocol: "tcp", fromPort: 80, toPort: 80, cidrBlocks: ["0.0.0.0/0"] }],
});

const server = new aws.ec2.Instance("web-server", {
    ami: "ami-6869aa05",
    instanceType: "t2.micro",
    vpcSecurityGroupIds: [ group.name ], // reference the security group resource above
});

export const publicIp = server.publicIp;
export const publicDns = server.publicDns;
import pulumi
import pulumi_aws as aws

group = aws.ec2.SecurityGroup('web-sg',
    description='Enable HTTP access',
    ingress=[
        { 'protocol': 'tcp', 'from_port': 80, 'to_port': 80, 'cidr_blocks': ['0.0.0.0/0'] }
    ])

server = aws.ec2.Instance('web-server',
    ami='ami-6869aa05',
    instance_type='t2.micro',
    vpc_security_group_ids=[group.name] # reference the security group resource above
)

pulumi.export('public_ip', server.public_ip)
pulumi.export('public_dns', server.public_dns)
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v4/go/aws/ec2"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		group, err := ec2.NewSecurityGroup(ctx, "web-sg", &ec2.SecurityGroupArgs{
			Description: pulumi.String("Enable HTTP access"),
			Ingress: ec2.SecurityGroupIngressArray{
				ec2.SecurityGroupIngressArgs{
					Protocol:   pulumi.String("tcp"),
					FromPort:   pulumi.Int(80),
					ToPort:     pulumi.Int(80),
					CidrBlocks: pulumi.StringArray{pulumi.String("0.0.0.0/0")},
				},
			},
		})
		if err != nil {
			return err
		}
		server, err := ec2.NewInstance(ctx, "web-server", &ec2.InstanceArgs{
			Ami:                 pulumi.String("ami-6869aa05"),
			InstanceType:        pulumi.String("t2.micro"),
			VpcSecurityGroupIds: pulumi.StringArray{group.Name},
		})
		if err != nil {
			return err
        }

		ctx.Export("publicIp", server.PublicIp)
		ctx.Export("publicHostName", server.PublicDns)
		return nil
	})
}
using System.Threading.Tasks;
using Pulumi;
using Pulumi.Aws.Ec2;
using Pulumi.Aws.Ec2.Inputs;

class Program
{
    static Task<int> Main() => Deployment.RunAsync<MyStack>();
}

class MyStack : Stack
{
    public MyStack()
    {
        var group = new SecurityGroup("web-sg", new SecurityGroupArgs {
            Description = "Enable HTTP access",
            Ingress = {
                new SecurityGroupIngressArgs {
                    Protocol = "tcp",
                    FromPort = 80,
                    ToPort = 80,
                    CidrBlocks = { "0.0.0.0/0" }
                }
            }
        });
        var server = new Instance("web-server", new InstanceArgs {
            Ami = "ami-6869aa05",
            InstanceType = "t2.micro",
            VpcSecurityGroupIds = { group.Name }
        });
        this.PublicIp = server.PublicIp;
        this.PublicDns = server.PublicDns;
    }

    [Output]
    public Output<string> PublicIp { get; set; }

    [Output]
    public Output<string> PublicDns { get; set; }
}

Concept Details

The following topics provide more details on the core concepts of Pulumi and how to use it:

Projects

Learn how Pulumi projects are organized and configured.

Stacks

Learn how to create and deploy stacks.

State and Backends

Learn how Pulumi stores state and manages concurrency.

Resources

Learn more about how to use and manage resources in your program.

Inputs and Outputs

Learn how to use resource properties to handle dependencies between resources.

Configuration

Learn how to configure stacks for different deployment scenarios.

Secrets

Learn how to handle sensitive data and how to store secret encrypted settings in Pulumi.

Assets and Archives

Learn about to use local or remote files with your Pulumi program.

Function Serialization

Learn how to serialize JavaScript functions into an artifact that can be used at runtime in the cloud.

Logging

Learn about how to access log information for diagnostics and debugging.

Pulumi Architecture

Learn about the internal Pulumi components used to performs deployments.