Pulumi, unlike its declarative cousins, lets you describe your cloud infrastructure using familiar programming languages, but the real magic is how it tracks and manages the state of that infrastructure across multiple deployments.
Let’s spin up a simple S3 bucket on AWS.
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 bucket name
pulumi.export("bucket_name", bucket.id)
When you run pulumi up, Pulumi doesn’t just send API calls to AWS. It first generates a desired state from your code and compares it to the current state of your infrastructure (stored in a backend like S3, or Pulumi’s own service). If there are differences, it calculates the minimal set of changes needed to reach the desired state.
Here’s what that looks like in action. Imagine you’ve run the above code once. Pulumi stores the state:
{
"version": 1,
"kind": "state",
"metadata": {
"version": "v3.34.0",
"tool": {
"name": "pulumi",
"version": "v3.34.0",
"runtime": "python"
},
"project": "my-project",
"stack": "dev"
},
"resources": [
{
"type": "aws:s3/bucket:Bucket",
"name": "my-bucket",
"id": "my-bucket-xxxxxxxxxxxx", // Actual bucket name will be here
"urn": "urn:pulumi:dev::my-project::aws:s3/bucket:Bucket::my-bucket",
"outputs": {
"bucket": "my-bucket-xxxxxxxxxxxx",
"bucketDomainName": "my-bucket-xxxxxxxxxxxx.s3.amazonaws.com",
"arn": "arn:aws:s3:::my-bucket-xxxxxxxxxxxx",
"id": "my-bucket-xxxxxxxxxxxx"
},
"dependencies": [],
"propertyDependencies": {
"bucket": [],
"acl": [],
"tags": []
}
}
],
"outputs": {
"bucket_name": "my-bucket-xxxxxxxxxxxx"
},
"remote": {
"type": "pulumi::pulumi::RemoteComponent",
"version": "0.0.0",
"physicalId": "urn:pulumi:dev::my-project::pulumi:pulumi:RemoteComponent::my-bucket-remote"
}
}
Now, let’s say you change the acl to "public-read" in your Python code and run pulumi up again. Pulumi reads this state file, compares it to your new code, sees that only the acl property needs to change for the my-bucket resource, and makes a targeted API call to AWS to update the bucket’s ACL.
The core problem Pulumi solves is managing the drift between your intended infrastructure (your code) and the actual deployed infrastructure. It uses a state file to keep track of what it thinks is deployed. This state file is crucial; if you lose it, Pulumi loses its memory of what it manages, and you can’t update or delete resources gracefully.
The mental model is a continuous loop:
- Code: You write infrastructure as code.
- Preview: Pulumi compares your code to the current state and shows you what will change.
- Update: Pulumi executes the planned changes by interacting with cloud provider APIs.
- State Update: Pulumi records the new actual state after the update.
This loop ensures that your infrastructure remains in sync with your code. You can also use Pulumi to manage infrastructure that wasn’t initially created by Pulumi. This is done using "import" commands, where you tell Pulumi about an existing resource, and it adds it to its state file.
The way Pulumi handles dependencies is also key. If you create a VPC and then a subnet within that VPC, Pulumi understands that the subnet depends on the VPC. It will ensure the VPC is created first, and only then will it attempt to create the subnet, preventing errors. This dependency graph is built dynamically from your code.
A subtle but powerful aspect is how Pulumi handles resource replacement. If you change a property that a cloud provider deems immutable (like changing the instance type of an EC2 instance), Pulumi won’t just try to update it. It will recognize that the resource needs to be replaced. It will then orchestrate a process where it first creates a new resource with the desired properties and, once that’s successful, it will delete the old resource. This is controlled by the replace_triggered_by option in some resource configurations.
The next step is understanding how to manage secrets within your infrastructure code, as plain text credentials in state files are a major security risk.