pulumi-stacks

Manage multiple environments and configurations with Pulumi stacks for consistent infrastructure across development, staging, and production.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "pulumi-stacks" with this command: npx skills add thebushidocollective/han/thebushidocollective-han-pulumi-stacks

Pulumi Stacks

Manage multiple environments and configurations with Pulumi stacks for consistent infrastructure across development, staging, and production.

Overview

Pulumi stacks are isolated, independently configurable instances of a Pulumi program. Each stack has its own state, configuration, and resources, enabling you to deploy the same infrastructure code to multiple environments.

Stack Basics

Creating and Selecting Stacks

Initialize a new project

pulumi new aws-typescript

Create a new stack

pulumi stack init dev

List all stacks

pulumi stack ls

Select a stack

pulumi stack select dev

Show current stack

pulumi stack

Remove a stack

pulumi stack rm dev

Stack Configuration

Set configuration values

pulumi config set aws:region us-east-1 pulumi config set instanceType t3.micro

Set secret values (encrypted)

pulumi config set --secret dbPassword mySecurePassword123

Get configuration values

pulumi config get aws:region

List all configuration

pulumi config

Remove configuration

pulumi config rm instanceType

Stack Configuration Files

Pulumi.yaml (Project File)

name: my-infrastructure user-invocable: false runtime: nodejs description: Multi-environment infrastructure

config: aws:region: description: AWS region for deployment default: us-east-1 instanceType: description: EC2 instance type default: t3.micro environment: description: Environment name

Pulumi.dev.yaml (Stack Config)

config: aws:region: us-east-1 my-infrastructure:instanceType: t3.micro my-infrastructure:environment: development my-infrastructure:minSize: "1" my-infrastructure:maxSize: "3" my-infrastructure:enableMonitoring: "false"

Pulumi.staging.yaml

config: aws:region: us-east-1 my-infrastructure:instanceType: t3.small my-infrastructure:environment: staging my-infrastructure:minSize: "2" my-infrastructure:maxSize: "5" my-infrastructure:enableMonitoring: "true"

Pulumi.prod.yaml

config: aws:region: us-west-2 my-infrastructure:instanceType: t3.medium my-infrastructure:environment: production my-infrastructure:minSize: "3" my-infrastructure:maxSize: "10" my-infrastructure:enableMonitoring: "true" my-infrastructure:backupRetention: "30"

Reading Configuration in Code

TypeScript Configuration

import * as pulumi from "@pulumi/pulumi"; import * as aws from "@pulumi/aws";

// Get configuration const config = new pulumi.Config(); const instanceType = config.get("instanceType") || "t3.micro"; const environment = config.require("environment"); const minSize = config.getNumber("minSize") || 1; const maxSize = config.getNumber("maxSize") || 3; const enableMonitoring = config.getBoolean("enableMonitoring") || false;

// Get secret const dbPassword = config.requireSecret("dbPassword");

// Use configuration const instance = new aws.ec2.Instance("web-server", { instanceType: instanceType, ami: "ami-0c55b159cbfafe1f0", tags: { Name: web-server-${environment}, Environment: environment, }, monitoring: enableMonitoring, });

// Export stack name export const stackName = pulumi.getStack(); export const instanceId = instance.id;

Python Configuration

import pulumi import pulumi_aws as aws

Get configuration

config = pulumi.Config() instance_type = config.get("instanceType") or "t3.micro" environment = config.require("environment") min_size = config.get_int("minSize") or 1 max_size = config.get_int("maxSize") or 3 enable_monitoring = config.get_bool("enableMonitoring") or False

Get secret

db_password = config.require_secret("dbPassword")

Use configuration

instance = aws.ec2.Instance( "web-server", instance_type=instance_type, ami="ami-0c55b159cbfafe1f0", tags={ "Name": f"web-server-{environment}", "Environment": environment, }, monitoring=enable_monitoring, )

Export outputs

pulumi.export("stack_name", pulumi.get_stack()) pulumi.export("instance_id", instance.id)

Environment-Specific Resources

Conditional Resource Creation

import * as pulumi from "@pulumi/pulumi"; import * as aws from "@pulumi/aws";

const config = new pulumi.Config(); const environment = config.require("environment"); const enableHighAvailability = config.getBoolean("enableHA") || false;

// Create VPC const vpc = new aws.ec2.Vpc("main", { cidrBlock: "10.0.0.0/16", tags: { Name: vpc-${environment}, Environment: environment, }, });

// Production gets multiple availability zones const azCount = environment === "production" ? 3 : 1; const subnets: aws.ec2.Subnet[] = [];

for (let i = 0; i < azCount; i++) { const subnet = new aws.ec2.Subnet(subnet-${i}, { vpcId: vpc.id, cidrBlock: 10.0.${i}.0/24, availabilityZone: us-east-1${String.fromCharCode(97 + i)}, tags: { Name: subnet-${environment}-${i}, Environment: environment, }, }); subnets.push(subnet); }

// Only create NAT gateway in production let natGateway: aws.ec2.NatGateway | undefined; if (environment === "production") { const eip = new aws.ec2.Eip("nat-eip", { vpc: true, });

natGateway = new aws.ec2.NatGateway("nat", {
    allocationId: eip.id,
    subnetId: subnets[0].id,
    tags: {
        Name: `nat-${environment}`,
        Environment: environment,
    },
});

}

// Create RDS with multi-AZ only in production const db = new aws.rds.Instance("database", { engine: "postgres", engineVersion: "14.7", instanceClass: environment === "production" ? "db.t3.medium" : "db.t3.micro", allocatedStorage: environment === "production" ? 100 : 20, dbName: "myapp", username: "admin", password: config.requireSecret("dbPassword"), multiAz: environment === "production", backupRetentionPeriod: environment === "production" ? 30 : 7, skipFinalSnapshot: environment !== "production", tags: { Name: db-${environment}, Environment: environment, }, });

export const vpcId = vpc.id; export const subnetIds = subnets.map(s => s.id); export const dbEndpoint = db.endpoint;

Stack References

Cross-Stack References

// Infrastructure stack (infra/index.ts) import * as pulumi from "@pulumi/pulumi"; import * as aws from "@pulumi/aws";

const vpc = new aws.ec2.Vpc("shared-vpc", { cidrBlock: "10.0.0.0/16", tags: { Name: "shared-vpc", }, });

const subnet = new aws.ec2.Subnet("shared-subnet", { vpcId: vpc.id, cidrBlock: "10.0.1.0/24", tags: { Name: "shared-subnet", }, });

// Export for other stacks export const vpcId = vpc.id; export const subnetId = subnet.id; export const vpcCidr = vpc.cidrBlock;

// Application stack (app/index.ts) import * as pulumi from "@pulumi/pulumi"; import * as aws from "@pulumi/aws";

// Reference infrastructure stack const infraStack = new pulumi.StackReference("myorg/infra/prod");

// Get outputs from infrastructure stack const vpcId = infraStack.getOutput("vpcId"); const subnetId = infraStack.getOutput("subnetId");

// Use referenced values const securityGroup = new aws.ec2.SecurityGroup("app-sg", { vpcId: vpcId, description: "Security group for application", ingress: [{ protocol: "tcp", fromPort: 80, toPort: 80, cidrBlocks: ["0.0.0.0/0"], }], });

const instance = new aws.ec2.Instance("app-server", { instanceType: "t3.micro", ami: "ami-0c55b159cbfafe1f0", subnetId: subnetId, vpcSecurityGroupIds: [securityGroup.id], tags: { Name: "app-server", }, });

export const instanceIp = instance.publicIp;

Stack Reference Commands

Deploy infrastructure stack first

cd infra pulumi stack select prod pulumi up

Then deploy application stack

cd ../app pulumi stack select prod pulumi up

View outputs from referenced stack

pulumi stack output --stack myorg/infra/prod

Stack Outputs

Exporting Stack Outputs

import * as pulumi from "@pulumi/pulumi"; import * as aws from "@pulumi/aws";

const config = new pulumi.Config(); const environment = config.require("environment");

// Create resources const vpc = new aws.ec2.Vpc("main", { cidrBlock: "10.0.0.0/16", });

const bucket = new aws.s3.Bucket("app-bucket", { bucket: myapp-${environment}-bucket, });

const db = new aws.rds.Instance("database", { engine: "postgres", instanceClass: "db.t3.micro", allocatedStorage: 20, dbName: "myapp", username: "admin", password: config.requireSecret("dbPassword"), skipFinalSnapshot: true, });

// Export outputs export const vpcId = vpc.id; export const vpcCidr = vpc.cidrBlock; export const bucketName = bucket.id; export const bucketArn = bucket.arn; export const dbEndpoint = db.endpoint; export const dbPort = db.port;

// Export computed values export const dbConnectionString = pulumi.interpolatepostgresql://admin@${db.endpoint}/myapp;

// Export stack metadata export const stackName = pulumi.getStack(); export const projectName = pulumi.getProject(); export const region = aws.getRegion().then(r => r.name);

Accessing Stack Outputs

View all outputs

pulumi stack output

Get specific output

pulumi stack output vpcId

Get output as JSON

pulumi stack output --json

Use in shell scripts

VPC_ID=$(pulumi stack output vpcId) echo "VPC ID: $VPC_ID"

Export to environment variables

export $(pulumi stack output --json | jq -r 'to_entries[] | "(.key)=(.value)"')

Stack Transformations

Global Resource Transformations

import * as pulumi from "@pulumi/pulumi"; import * as aws from "@pulumi/aws";

const config = new pulumi.Config(); const environment = config.require("environment");

// Register global transformation to add tags pulumi.runtime.registerStackTransformation((args) => { if (args.type.startsWith("aws:")) { args.props.tags = { ...args.props.tags, Environment: environment, ManagedBy: "Pulumi", Stack: pulumi.getStack(), }; } return { props: args.props, opts: args.opts, }; });

// All AWS resources automatically get tags const vpc = new aws.ec2.Vpc("main", { cidrBlock: "10.0.0.0/16", // tags will be automatically added by transformation });

const bucket = new aws.s3.Bucket("data", { // tags will be automatically added by transformation });

Resource-Specific Transformations

import * as pulumi from "@pulumi/pulumi"; import * as aws from "@pulumi/aws";

const config = new pulumi.Config(); const environment = config.require("environment");

// Transformation to enforce encryption const enforceEncryption = (args: pulumi.ResourceTransformationArgs) => { if (args.type === "aws:s3/bucket:Bucket") { args.props.serverSideEncryptionConfiguration = { rule: { applyServerSideEncryptionByDefault: { sseAlgorithm: "AES256", }, }, }; }

if (args.type === "aws:rds/instance:Instance") {
    args.props.storageEncrypted = true;
}

return {
    props: args.props,
    opts: args.opts,
};

};

pulumi.runtime.registerStackTransformation(enforceEncryption);

// Resources will be automatically encrypted const bucket = new aws.s3.Bucket("data"); const db = new aws.rds.Instance("database", { engine: "postgres", instanceClass: "db.t3.micro", allocatedStorage: 20, });

Stack Tags and Organization

Tagging Strategy

import * as pulumi from "@pulumi/pulumi"; import * as aws from "@pulumi/aws";

const config = new pulumi.Config(); const environment = config.require("environment"); const project = pulumi.getProject(); const stack = pulumi.getStack();

// Define common tags const commonTags = { Project: project, Environment: environment, Stack: stack, ManagedBy: "Pulumi", CostCenter: config.get("costCenter") || "engineering", Owner: config.get("owner") || "platform-team", };

// Helper function to merge tags function mergeTags(resourceTags?: { [key: string]: string }): { [key: string]: string } { return { ...commonTags, ...resourceTags, }; }

// Use consistent tagging const vpc = new aws.ec2.Vpc("main", { cidrBlock: "10.0.0.0/16", tags: mergeTags({ Name: vpc-${environment}, Type: "network", }), });

const bucket = new aws.s3.Bucket("data", { tags: mergeTags({ Name: data-${environment}, Type: "storage", Compliance: "required", }), });

const db = new aws.rds.Instance("database", { engine: "postgres", instanceClass: "db.t3.micro", allocatedStorage: 20, tags: mergeTags({ Name: db-${environment}, Type: "database", BackupRequired: "true", }), });

Stack Import and Export

Exporting Stack State

Export stack state to JSON

pulumi stack export > stack-state.json

Export to file

pulumi stack export --file stack-backup.json

Export with secrets in plaintext (use carefully!)

pulumi stack export --show-secrets > stack-with-secrets.json

Importing Stack State

Import stack state

pulumi stack import --file stack-state.json

Import from stdin

cat stack-state.json | pulumi stack import

Stack Migration

Export from old stack

pulumi stack select old-stack pulumi stack export --file old-stack.json

Create and import to new stack

pulumi stack init new-stack pulumi stack import --file old-stack.json

Verify resources

pulumi preview

Multi-Region Deployments

Region-Specific Stacks

import * as pulumi from "@pulumi/pulumi"; import * as aws from "@pulumi/aws";

const config = new pulumi.Config(); const awsConfig = new pulumi.Config("aws"); const region = awsConfig.require("region"); const environment = config.require("environment");

// Create region-specific resources const vpc = new aws.ec2.Vpc(vpc-${region}, { cidrBlock: "10.0.0.0/16", tags: { Name: vpc-${environment}-${region}, Region: region, Environment: environment, }, });

// Create CloudFront distribution in us-east-1 const usEast1Provider = new aws.Provider("us-east-1", { region: "us-east-1", });

const certificate = new aws.acm.Certificate("cert", { domainName: ${environment}.example.com, validationMethod: "DNS", tags: { Name: cert-${environment}, Environment: environment, }, }, { provider: usEast1Provider });

// Export region info export const deploymentRegion = region; export const vpcId = vpc.id; export const certificateArn = certificate.arn;

Multi-Region Stack Configuration

Pulumi.us-east-1-prod.yaml

config: aws:region: us-east-1 my-app:environment: production my-app:isPrimaryRegion: "true"

Pulumi.us-west-2-prod.yaml

config: aws:region: us-west-2 my-app:environment: production my-app:isPrimaryRegion: "false"

Pulumi.eu-west-1-prod.yaml

config: aws:region: eu-west-1 my-app:environment: production my-app:isPrimaryRegion: "false"

Stack Policies

Protect Resources

import * as pulumi from "@pulumi/pulumi"; import * as aws from "@pulumi/aws";

const config = new pulumi.Config(); const environment = config.require("environment");

// Protect production databases const db = new aws.rds.Instance("database", { engine: "postgres", instanceClass: "db.t3.micro", allocatedStorage: 20, tags: { Name: db-${environment}, }, }, { protect: environment === "production", });

// Protect production storage const bucket = new aws.s3.Bucket("data", { tags: { Name: data-${environment}, }, }, { protect: environment === "production", });

Retain Resources

import * as pulumi from "@pulumi/pulumi"; import * as aws from "@pulumi/aws";

const config = new pulumi.Config(); const environment = config.require("environment");

// Retain production databases on stack deletion const db = new aws.rds.Instance("database", { engine: "postgres", instanceClass: "db.t3.micro", allocatedStorage: 20, finalSnapshotIdentifier: environment === "production" ? final-snapshot-${Date.now()} : undefined, skipFinalSnapshot: environment !== "production", }, { retainOnDelete: environment === "production", });

Stack Secrets Management

Using Encrypted Secrets

Set encrypted secrets

pulumi config set --secret dbPassword mySecurePassword123 pulumi config set --secret apiKey sk_live_abc123xyz789

View config (secrets are encrypted)

pulumi config

View secrets in plaintext (use carefully!)

pulumi config get dbPassword --show-secrets

Secrets in Code

import * as pulumi from "@pulumi/pulumi"; import * as aws from "@pulumi/aws";

const config = new pulumi.Config();

// Get secret values const dbPassword = config.requireSecret("dbPassword"); const apiKey = config.requireSecret("apiKey");

// Use secrets in resources const db = new aws.rds.Instance("database", { engine: "postgres", instanceClass: "db.t3.micro", allocatedStorage: 20, username: "admin", password: dbPassword, });

// Create SSM parameters from secrets const dbPasswordParam = new aws.ssm.Parameter("db-password", { name: "/app/database/password", type: "SecureString", value: dbPassword, });

const apiKeyParam = new aws.ssm.Parameter("api-key", { name: "/app/api/key", type: "SecureString", value: apiKey, });

// Secrets are encrypted in state export const connectionString = pulumi.secret( pulumi.interpolatepostgresql://admin:${dbPassword}@${db.endpoint}/myapp );

Stack Refresh and State

Refresh Stack State

Refresh stack to match actual cloud state

pulumi refresh

Refresh with auto-approval

pulumi refresh --yes

Refresh specific resources

pulumi refresh --target urn:pulumi:dev::myapp::aws:s3/bucket:Bucket::my-bucket

Refresh and show diff

pulumi refresh --diff

Stack State Management

View stack state

pulumi stack --show-urns

View specific resource

pulumi stack --show-urns | grep my-bucket

Remove resource from state (doesn't delete cloud resource)

pulumi state delete 'urn:pulumi:dev::myapp::aws:s3/bucket:Bucket::my-bucket'

Rename resource in state

pulumi state rename 'urn:pulumi:dev::myapp::aws:s3/bucket:Bucket::old-name'
'urn:pulumi:dev::myapp::aws:s3/bucket:Bucket::new-name'

When to Use This Skill

Use the pulumi-stacks skill when you need to:

  • Deploy infrastructure to multiple environments (dev, staging, prod)

  • Manage environment-specific configurations

  • Create isolated instances of the same infrastructure

  • Share infrastructure outputs between projects

  • Implement multi-region deployments

  • Separate infrastructure concerns (networking, databases, applications)

  • Manage secrets per environment

  • Track infrastructure state per environment

  • Implement progressive deployment strategies

  • Organize complex infrastructure into manageable units

  • Apply environment-specific policies and protections

  • Maintain consistent infrastructure across environments

Best Practices

  • Naming Convention: Use consistent stack naming like <env> or <region>-<env> (e.g., prod , us-east-1-prod )

  • Configuration Files: Keep stack config files in version control (except secrets)

  • Environment Isolation: Never share state between environments; each environment gets its own stack

  • Stack References: Use stack references instead of duplicating infrastructure code

  • Secrets Management: Always use --secret flag for sensitive values

  • Progressive Deployment: Deploy to dev first, then staging, finally production

  • State Backups: Regularly export stack state for disaster recovery

  • Resource Protection: Enable protect option for critical production resources

  • Tagging Strategy: Apply consistent tags across all environments for cost tracking

  • Stack Outputs: Export all values needed by other stacks or external systems

  • Configuration Validation: Validate configuration values before creating resources

  • Environment Parity: Keep environments as similar as possible, differing only in scale

  • Automation: Use CI/CD pipelines for stack deployments

  • Documentation: Document stack dependencies and required configuration

  • State Encryption: Use encrypted state backends for sensitive infrastructure

Common Pitfalls

  • Hardcoded Values: Hardcoding environment-specific values instead of using configuration

  • Shared State: Attempting to share stack state between environments

  • Missing Config: Deploying to new stack without setting required configuration

  • Unencrypted Secrets: Storing secrets as plain text in configuration

  • Inconsistent Naming: Using different naming conventions across stacks

  • Broken References: Stack references that point to non-existent stacks or outputs

  • Missing Exports: Not exporting values needed by dependent stacks

  • Config Drift: Manual changes to config files not reflected in version control

  • No Resource Protection: Forgetting to protect critical production resources

  • Stack Sprawl: Creating too many stacks without clear organization

  • Missing Validation: Not validating configuration before deployment

  • Circular Dependencies: Creating circular stack references

  • No Backup Strategy: Not exporting stack state for disaster recovery

  • Environment Differences: Production significantly different from other environments

  • Poor Secret Management: Checking encrypted secrets into public repositories without proper key management

Resources

  • Pulumi Stack Documentation

  • Pulumi Configuration

  • Stack References

  • Pulumi Secrets

  • Stack Transformations

  • Organizing Projects and Stacks

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

typescript-type-system

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

typescript-async-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

c-systems-programming

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

cpp-templates-metaprogramming

No summary provided by upstream source.

Repository SourceNeeds Review