Pulumi stacks are designed to provide safe isolation between your different deployment environments, like development, staging, and production.
Let’s see this in action. Imagine you have a Pulumi program that deploys a simple S3 bucket.
import pulumi
import pulumi_aws as aws
# Get the current stack name
stack_name = pulumi.get_stack()
# Create an S3 bucket
bucket = aws.s3.Bucket(f"my-bucket-{stack_name}",
acl="private",
tags={
"Environment": stack_name,
})
# Export the bucket name
pulumi.export("bucket_name", bucket.id)
Now, let’s create two distinct stacks from this program.
First, for development:
pulumi stack init dev
pulumi up
This will create a bucket named something like my-bucket-dev-a1b2c3d4.
Next, for staging:
pulumi stack init staging
pulumi up
This will create a separate bucket, perhaps named my-bucket-staging-e5f6g7h8. The key here is that the pulumi stack init command not only initializes a new set of configuration and state for that stack but also creates a unique namespace for your resources.
The Pulumi engine uses the stack name to disambiguate resources. When you run pulumi up within the dev stack, Pulumi looks at the state file associated with dev and only considers resources managed by that specific stack. If you switch to the staging stack using pulumi stack select staging and run pulumi up again, Pulumi will consult the staging stack’s state file. This separation is fundamental. If a resource name conflicts between stacks (like two buckets named my-bucket), Pulumi automatically appends a unique identifier to one of them to ensure they don’t collide within the cloud provider’s API. This is why you’ll see seemingly random characters appended to resource names – it’s Pulumi ensuring uniqueness across your deployments.
The isolation isn’t just about naming. Each stack maintains its own independent configuration and state. You can set different AWS region configurations for each stack, for instance.
# While in the 'dev' stack
pulumi config set aws:region us-east-1
# While in the 'staging' stack
pulumi config set aws:region us-west-2
When you pulumi up, the correct region is used for that stack’s deployment because the configuration is tied to the stack itself, not the Pulumi program. This means your dev stack can deploy resources in us-east-1 while your staging stack deploys identical resources in us-west-2, all from the same Pulumi code.
The state file, stored securely by the Pulumi Service (or your self-managed backend), is the source of truth for each stack. It contains the inventory of all resources managed by that specific stack and their current desired state. When you run pulumi up, Pulumi compares the desired state defined in your code with the actual state recorded in the stack’s state file and then calculates the minimal set of changes needed to reconcile them. This is how Pulumi achieves efficient and safe updates without accidentally affecting resources managed by other stacks.
What most people overlook is how deeply the stack’s identity permeates the Pulumi engine’s behavior. It’s not just a label; it influences resource naming, configuration resolution, state management, and even the secrets backend used for sensitive configuration values. Each stack is a completely independent deployment unit, even if they share the same underlying Pulumi code and cloud provider account.
The next step in managing multiple environments is understanding how to share components and configurations across stacks using Pulumi’s component resources and policy-as-code features.