Managing Environment Isolation with Pulumi Stacks
Learn how Pulumi Stacks isolate environments via dedicated state files and stack-specific configuration, preventing accidental cross-environment changes.
06 Dec 2025, 23:26 UTC

Solving the Environment Leakage Problem
The primary challenge in Infrastructure as Code (IaC) is deploying the same architectural pattern across multiple environments—such as development, staging, and production—without hard-coding values or risking accidental modifications to live systems. If you use a single state file for all environments, a mistake in a development script can inadvertently destroy production resources.
The solution is the Pulumi Stack. A stack is an isolated instance of your Pulumi program. It combines a specific set of configuration values with a dedicated state file, ensuring that changes to your 'dev' stack have zero physical or logical impact on your 'prod' stack.
How Stacks Isolate State and Configuration
When you run a Pulumi program, the engine looks for the active stack context. This context determines two things: which Pulumi.<stack-name>.yaml file to read for variables and which state file to use to track existing cloud resources.
Worked Example: Environment-Specific Instance Sizing
Consider a scenario where you need a small instance for development and a high-performance instance for production. Instead of writing two separate programs, you use a single program that pulls values from the stack configuration.
1. Initialize the stacks
Run these commands in your terminal (requires Pulumi CLI installed and cloud provider credentials configured):
# Create the development stack
pulumi stack init dev
# Create the production stack
pulumi stack init prod
2. Set stack-specific configuration
Use the config set command to assign different values to each stack. This creates separate YAML files in your project root.
# Select dev and set size
pulumi stack select dev
pulumi config set instanceSize t3.micro
# Select prod and set size
pulumi stack select prod
pulumi config set instanceSize m5.large
3. Implement the logic in code
In your Pulumi program (TypeScript example), use the pulumi.Config class to retrieve these values at runtime.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
// Initialize the config object
const config = new pulumi.Config();
// Retrieve the instanceSize value for the current active stack
const instanceSize = config.require("instanceSize");
const server = new aws.ec2.Instance("web-server", {
instanceType: instanceSize,
ami: "ami-0c55b159cbfafe1f0", // Example AMI
});
export "serverIp" = server.publicIp;
4. Deployment and Verification
To deploy to a specific environment, select the stack before running the update:
pulumi stack select dev
pulumi up
# To verify, check the cloud console for a t3.micro instance.
# Then switch to production:
pulumi stack select prod
pulumi up
# Verify a separate m5.large instance exists.
Advanced Isolation: Stack References
In complex architectures, you may want to separate your network (VPC) into one stack and your application into another. This prevents a change to an app server from risking a change to the core network. You can achieve this using Stack References, which allow one stack to read the exported outputs of another.
If the network-stack exports a vpcId, the app-stack can access it like this:
const networkStack = new pulumi.StackReference("organization/network-stack/prod");
const vpcId = networkStack.getOutput("vpcId");
Limitations and Common Pitfalls
- State File Bloat: Putting too many resources into a single stack can lead to slow
pulumi uptimes and increased risk of state locking contention during team collaborations. Break large infrastructures into smaller, logically grouped stacks. - The "Active Stack" Trap: The most common cause of production outages is running
pulumi upwhile the CLI is still pointed at theprodstack after a developer finished a task. Always runpulumi stack lsto verify your current context. - Secret Leakage: Standard config values are stored in plain text in the
Pulumi.<stack>.yamlfile. For passwords or API keys, usepulumi config set --secret <key> <value>to ensure values are encrypted at rest.
Verification Checklist
| Check | Action | Expected Result |
|---|---|---|
| Config Isolation | Compare Pulumi.dev.yaml and Pulumi.prod.yaml |
Different values for the same keys. |
| Resource Uniqueness | Check Cloud Provider Console | Two distinct sets of resources with different tags/sizes. |
| State Separation | Run pulumi stack export for both stacks |
Two different JSON state files. |
Rollback Procedure
If a stack deployment fails or causes instability, you can revert the infrastructure to the previous known-good state using the state history:
- Identify the last stable update number via
pulumi stack history. - Use
pulumi stack importto restore a previous state file, or more commonly, revert the code change in Git and runpulumi upto let the engine reconcile the state back to the previous configuration.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.