2.6. Stacks
Stacks are Pulumi’s mechanism for running the same program against isolated environments — dev, staging, and prod
each get their own state, their own config, and their own deployed resources.
Step 1 — Inspect the current stack
Check which stack is currently active and list all stacks in the project:
Explanation
Every Pulumi operation targets exactly one stack. pulumi stack prints the active stack and its last-known
resource count. pulumi stack ls shows all stacks that exist in the current backend for this project.
At this point you should see a single stack — dev — marked as current with an asterisk. The dev container
is still running on port 8080 — leave it up.
Each stack can bind a different port
Because the port is a config value, dev uses 8080 and prod will use 8081 — both can run simultaneously on
the same Docker host. In real cloud environments the isolation is even stronger: each stack provisions resources
in its own resource group, so stacks never compete for the same network port at all.
Step 2 — Create a prod stack
Create a new isolated stack named prod:
Explanation
pulumi stack init creates a new stack entry in the state backend. The new stack is completely empty — no
resources, no config, no history from dev. The stacks share the same Python program but maintain separate
state files.
After init, prod becomes the active stack automatically. You should see both stacks in pulumi stack ls,
with prod now marked as current.
A new config file appears: config/Pulumi.prod.yaml
pulumi stack init creates config/Pulumi.prod.yaml in your project. This file stores all config values
you set with pulumi config set while prod is active — image tags, region, any stack-specific settings.
Commit this file so the config travels with the code and other team members get the same values when they
select prod.
Config is per-stack
Stack config values set with pulumi config set apply only to the active stack. Values read with
config.require() or config.require_secret() must be set on every stack or have a default value in
Pulumi.yaml — Pulumi fails loudly if they are missing. Values read with config.get() or
config.get_object() are optional and fall back to their defaults.
Step 3 — Deploy to prod
Config is per-stack — prod starts with no values. Set the required config before deploying:
Run a preview and deploy:
Verify the resources and outputs are present in prod:
Confirm that the dev container is still running on port 8080:
Explanation
pulumi up targets whichever stack is currently active — prod in this case. Pulumi reads the empty prod
state, sees that none of the program’s resources exist yet, and creates them from scratch.
With port set to 8081 for prod and 8080 for dev, both containers run simultaneously on the same Docker
host. The dev stack is completely unaffected — its state file, container, and outputs remain exactly as they
were. This isolation is the core guarantee stacks provide: a deploy on one stack cannot modify resources
owned by another stack.
Step 4 — Switch back to dev
Select the dev stack and confirm its outputs are intact:
Explanation
pulumi stack select changes the active stack without touching any resources. All subsequent CLI commands
(pulumi up, pulumi preview, pulumi stack output, …) target the newly selected stack.
This is how teams manage multiple environments with a single codebase:
| Stack | Purpose |
|---|---|
dev | Individual or shared development; throwaway deploys |
staging | Pre-production; mirrors prod config and scale |
prod | Live environment; protected resources |
One stack per environment, one environment per stack
Avoid using feature branches to vary infrastructure. Use stacks instead — each stack carries its own config and
state, so a dev stack can use a cheaper VM size while prod uses the production tier, all in the same
program.
Step 5 — Destroy the prod stack
Tear down the resources in prod and remove the stack to keep the project tidy:
Confirm the stack is gone:
Explanation
pulumi destroy removes all resources owned by the active stack and clears them from state, but leaves the
empty stack record in the backend. pulumi stack rm deletes that record as well. After this sequence only
dev remains.
In production workflows, stacks like prod are never removed — they persist for the lifetime of the
environment. stack rm is mainly useful for cleaning up short-lived feature or test stacks.