In Pulumi, what is a stack, and how does one Pulumi program deploy separate dev, staging and production environments?
answer
- one program, many deployed instances
- per-environment values live in a file
- Pulumi.<stack>.yaml beside Pulumi.yaml
- separate state and outputs per stack
- org/project/stack is the full name
basics
~20 sA Pulumi stack is one independently configurable instance of a program, with its own config file, its own state and its own outputs. Running the same program against dev, staging and prod stacks gives three isolated deployments and no duplicated code.
solid answer
~40 sA Pulumi project is the program (`Pulumi.yaml` plus the code); a stack is one deployed instance of that program. Each stack gets its own config file, `Pulumi.<stack>.yaml`, its own state/checkpoint in the backend, and its own set of exported outputs. So you write the infrastructure once and create `pulumi stack init dev`, `staging`, `prod`; the differences — instance sizes, CIDR ranges, replica counts — live in each stack's config rather than in branched code. You pick the target with `pulumi stack select prod` or per-command with `-s prod` / `--stack prod`, and the program can read its own stack name via `pulumi.getStack()` if it genuinely needs to branch. Stacks are fully qualified as `<org>/<project>/<stack>`, which is also how another stack refers to them.
code
bash · 10 linespulumi stack init dev
pulumi config set aws:region eu-west-1
pulumi config set myapp:instanceType t3.small
pulumi stack init prod
pulumi config set aws:region eu-west-1
pulumi config set myapp:instanceType m6i.large
pulumi up --stack dev --yes
pulumi preview --stack prodgo deeper
Be able to say that a project is the program and a stack is one deployed instance of it, and that per-environment values live in Pulumi.<stack>.yaml. Know pulumi stack init, pulumi stack select and pulumi up --stack.
Explain the three things a stack owns — its config file, its own state, its own outputs — and why that isolation is what makes one program safe to run against dev and prod. Mention the fully qualified org/project/stack name.
Show judgment about estate shape: when to split one project into several, when a region deserves its own stack, and how you stop someone deploying to the wrong stack in CI. Talk about tearing down ephemeral stacks cleanly.
Own the tradeoff between few large stacks and many small ones: blast radius and deploy time against cross-stack coordination cost and permission boundaries. Be ready to defend where the environment boundary sits and who is allowed to run an update on each side of it.
## Project versus stack Pulumi splits "what the infrastructure is" from "which instance of it you are deploying". The **project** is the program: a `Pulumi.yaml` file naming the project and its runtime, plus the source code in TypeScript, Python, Go, C# or Java. The **stack** is one deployment of that project — dev, staging, prod, a per-developer sandbox, or the same environment in a second region. Nothing about a stack lives in the program's code by default. A stack is created with the CLI: ```bash pulumi stack init dev pulumi stack init prod pulumi stack ls ``` Each `stack init` creates a config file next to the project file and registers the stack in whatever backend you are logged into. ## What a stack owns Three things are per-stack, and this is the whole point of the concept: 1. **Config** — the file `Pulumi.<stack>.yaml`. Values are set with `pulumi config set`, namespaced by project name, and secret values are stored encrypted rather than in plaintext. 2. **State** — the checkpoint recording every resource the stack created, its inputs, outputs and provider. Two stacks of the same project never share a checkpoint, so an `up` on dev cannot touch prod's resources. 3. **Outputs** — the values the program exports. `pulumi stack output` shows the current stack's; another stack reads them through a stack reference. A minimal `Pulumi.prod.yaml` looks like this: ```yaml config: aws:region: eu-west-1 myapp:instanceType: m6i.large myapp:replicas: "6" ``` and `Pulumi.dev.yaml` differs only in the values. The program itself is unchanged. ## Selecting and running against a stack The CLI keeps a currently-selected stack per project: ```bash pulumi stack select dev pulumi up pulumi up --stack prod --yes ``` In CI you almost always pass `-s`/`--stack` explicitly rather than relying on the selected stack, because "selected" is workspace-local state that a fresh runner does not have. `pulumi preview` and `pulumi destroy` take the same flag. ## Reading the stack name in code The program can call `pulumi.getStack()` (`pulumi.get_stack()` in Python) to learn which stack it is running as, and `pulumi.getProject()` for the project name. Two legitimate uses: naming or tagging resources so a console user can tell environments apart, and gating something that only exists in one environment. It is a smell to grow a large `if (stack === "prod")` tree — that is config's job. Keep the code one shape and let the config file carry the differences. ## Fully qualified names A stack's full name is `<organization>/<project>/<stack>` — for example `acme/networking/prod`. When you are logged into a self-managed backend the organization part is literally `organization`. You need the fully qualified form when one stack reads another's outputs, and when scripting against several projects. ## Why not just branches or copies? Two common alternatives are worse. Copying the program per environment duplicates every future change and lets the copies drift. Using a git branch per environment means prod's code is whatever was last merged into that branch, and a change is only proven once it has already been promoted. Stacks keep one reviewed program and make the environment a runtime input, so the same code that passed in dev is the code that runs in prod. ## Practical patterns - **One stack per environment**, and one per environment *per region* if you deploy multi-region — each region's resources then have their own state and can be rolled independently. - **Ephemeral per-developer stacks** (`pulumi stack init alice-dev`) for sandbox work; tear down with `pulumi destroy` and then `pulumi stack rm`. Pulumi's auto-naming appends a random suffix to physical resource names, so several stacks of the same program coexist without name collisions. - **Split large estates into several projects** (networking, data, app), each with its own set of stacks, rather than one enormous project whose every `up` re-checks the whole estate. ## The failure modes to know Running against the wrong stack is the classic one: you selected `prod` yesterday, come back today and run `pulumi up`, and the diff is against production. Show the target in your prompt or always pass `-s`. The other is deleting a stack that still owns resources — `pulumi stack rm` refuses unless the stack is empty or you force it, and forcing it orphans real infrastructure that no longer appears in any state.
- Two developers each want a throwaway copy of the dev environment — how do you handle that with stacks?Give each one their own stack: `pulumi stack init alice-dev`, same program, its own config file, state and resources. Pulumi auto-names physical resources with a random suffix, so the copies don't collide. Clean up with `pulumi destroy` followed by `pulumi stack rm`, so no orphaned resources or stale checkpoints are left behind.
- Does adding a new environment require changing the program's code?Normally no. You run `pulumi stack init`, set the values with `pulumi config set`, and deploy the unchanged program. Code changes only if the new environment needs a structurally different resource graph, and even then prefer a config-driven conditional over a branch on `pulumi.getStack()`.
- What is the risk of relying on `pulumi stack select` in CI?The selected stack is local workspace state that a fresh runner does not have, and on a developer machine it silently persists between sessions — that is how someone runs `pulumi up` against prod by accident. Pass `--stack` explicitly on every CI command so the target is visible in the job definition.
saying these in an interview costs you the question
- Says a stack is just a naming prefix on resources
- Thinks all stacks of a project share one state file
- Copies the program per environment instead of adding a stack
- Branches heavily on pulumi.getStack() instead of using config
- Assumes the selected stack is safe to rely on in CI