The Pulumi AWS provider is how Pulumi talks to AWS. It’s not just a wrapper; it’s a declarative API that maps Pulumi resource types to AWS service APIs, managing the state of your infrastructure for you.

Let’s see it in action. Imagine you want to deploy a simple S3 bucket.

import pulumi
import pulumi_aws as aws

# Create an AWS resource (S3 Bucket)
bucket = aws.s3.Bucket("my-bucket",
    acl="private",
    tags={
        "Environment": "Dev",
    })

# Export the name of the bucket
pulumi.export("bucket_name", bucket.id)

When you run pulumi up with this code, Pulumi doesn’t just run aws s3 create-bucket. It consults its state file, checks if my-bucket already exists, and if not, it makes a CreateBucket API call to AWS. If the bucket already exists, it checks if the acl or tags have changed. If they have, it calls PutBucketAcl or PutBucketTagging. The id export makes the bucket’s actual name (which Pulumi generates if you don’t specify one) available after deployment.

This declarative approach lets you define your desired infrastructure state. Pulumi’s engine then figures out the minimal set of API calls needed to get AWS into that state. It handles dependencies automatically: if you define a security group and then an EC2 instance that uses that security group, Pulumi knows to create the security group before attempting to create the instance.

The core components you’ll interact with are:

  • Resource Types: These are Pulumi’s abstractions for AWS services. aws.s3.Bucket, aws.ec2.Instance, aws.iam.Role are examples. Each corresponds to a specific AWS resource.
  • Properties: These are the configurable attributes of a resource. For an aws.s3.Bucket, properties include acl, versioning, website, tags, etc. These map directly to AWS API parameters.
  • State Management: Pulumi maintains a state file (either in its service or a backend like S3) that tracks every resource it manages, its properties, and its unique ID in AWS. This is crucial for updates and deletions.
  • The Pulumi Engine: This is the orchestrator. It reads your code, compares the desired state to the current state (from the state file), plans the necessary changes (create, update, delete), and executes those changes by calling the AWS APIs via the Pulumi AWS provider.

The problem this solves is the inherent complexity and manual effort of managing cloud infrastructure. Instead of scripting aws cli commands or writing imperative code that has to track resource IDs and dependencies, you describe what you want, and Pulumi figures out how to get there. It brings the benefits of software engineering – version control, testing, repeatable deployments – to infrastructure management.

When you define a resource like aws.s3.Bucket("my-bucket", ...), Pulumi doesn’t create a resource named "my-bucket". It creates a Pulumi logical name "my-bucket" and then asks AWS to create a physical bucket. Pulumi then decides the actual physical name of the bucket, often by appending a random suffix to prevent collisions if you deploy the same stack multiple times or if another stack already uses that name. You can force a specific name using the bucket argument: aws.s3.Bucket("my-bucket", bucket="my-specific-bucket-name", ...).

The next step is understanding how to manage multiple AWS accounts and regions within a single Pulumi program.

Want structured learning?

Take the full Pulumi course →