You can write your cloud infrastructure using TypeScript, just like you write your application code.

Here’s a simple example of deploying a static S3 website using Pulumi with TypeScript. First, you’d install Pulumi and set up your AWS credentials. Then, you create a new Pulumi project:

mkdir pulumi-s3-example
cd pulumi-s3-example
pulumi new aws-typescript

This command scaffolds a new Pulumi project with TypeScript, creating index.ts (your main infrastructure file), package.json, and tsconfig.json.

Now, let’s define the S3 bucket and website configuration in index.ts:

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

// Create an S3 bucket for website content
const bucket = new aws.s3.Bucket("my-s3-bucket", {
    website: {
        indexDocument: "index.html",
    },
});

// Create a bucket object for the index.html file
const indexFile = new aws.s3.BucketObject("index.html", {
    bucket: bucket.bucket, // Reference the bucket name created above
    content: "<h1>Hello, Pulumi!</h1>",
    contentType: "text/html",
});

// Export the website endpoint
export const bucketEndpoint = pulumi.interpolate`http://${bucket.websiteEndpoint}`;

To deploy this, you’d run:

pulumi up

Pulumi will then show you a preview of the resources it’s going to create (an S3 bucket and an object within it) and ask for confirmation. Upon confirmation, it provisions the infrastructure in your AWS account.

The bucketEndpoint output will then be displayed, giving you the URL to access your new website.

The core problem Pulumi solves is the disconnect between how developers think about code and how infrastructure is traditionally managed. Using familiar programming languages like TypeScript allows infrastructure to be treated as code, enabling version control, testing, and reuse. It brings software engineering best practices to infrastructure management.

Internally, Pulumi works by taking your TypeScript code and compiling it down to a desired state. When you run pulumi up, the Pulumi engine analyzes your code, compares the desired state with the actual state of your cloud resources, and then generates a plan to reconcile any differences. This plan is executed by the respective cloud provider’s APIs (e.g., AWS, Azure, GCP). The state of your infrastructure is tracked by Pulumi in a state file, which is crucial for managing updates and deletions.

You control the infrastructure through the resources you instantiate from SDKs (like @pulumi/aws, @pulumi/azure, @pulumi/gcp) and their associated properties. For instance, in the S3 bucket example, website: { indexDocument: "index.html" } directly configures the S3 bucket’s static website hosting feature. You can define networking rules, databases, serverless functions, Kubernetes clusters, and much more, all within your TypeScript code.

What often surprises people is how Pulumi handles resource dependencies implicitly. When you reference an output of one resource as an input to another (like bucket: bucket.bucket for the BucketObject), Pulumi automatically understands that the BucketObject depends on the Bucket being created first. It orchestrates the creation and updates in the correct order without explicit dependency declarations, simplifying complex deployments significantly.

The next step is to explore how to manage secrets and configure different deployment environments using Pulumi’s configuration system.

Want structured learning?

Take the full Pulumi course →