
Pulumi Best Practices
Write and review Pulumi TypeScript or Python so previews stay predictable, dependencies order correctly, and refactors do not destroy cloud resources.
Overview
pulumi-best-practices is an agent skill most often used in Build (also Ship launch, Operate infra) that applies reliable Pulumi coding patterns for previews, dependencies, components, and safe refactors.
Install
npx skills add https://github.com/pulumi/agent-skills --skill pulumi-best-practicesWhat is this skill?
- Hard rule: never construct resources inside Output.apply() callbacks
- ComponentResource patterns for reusable infrastructure modules
- Aliases and refactor guidance to avoid accidental resource replacement
- Secrets and stack configuration setup without leaking values
- pulumi preview and pulumi up CI workflow conventions
- Documented practice #1: never create resources inside apply()
Adoption & trust: 1.3k installs on skills.sh; 56 GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
Your Pulumi stack previews lie or deployments fail because resources are created inside apply(), dependencies are implicit, and renames would destroy production data.
Who is it for?
Solo developers shipping TypeScript or Python Pulumi stacks who want review-grade IaC before every pulumi up.
Skip if: Raw Terraform/HCL-only workflows, one-click PaaS deploys with no IaC repo, or teams unwilling to run pulumi preview in CI.
When should I use this skill?
Writing, reviewing, or debugging Pulumi TypeScript/Python; questions about Output<T>, apply(), ComponentResource, aliases, secrets, config, or preview/up CI.
What do I get? / Deliverables
You refactor and extend Pulumi programs with preview-visible resources, explicit parent/child graphs, aliases, and CI-friendly preview/up workflows.
- Reviewed Pulumi module following anti-apply patterns
- ComponentResource layout
- CI preview gate configuration guidance
Recommended Skills
Journey fit
Spans multiple journey phases - primary shelf plus alternate fits below.
IaC authoring sits in Build/integrations as the primary shelf, while preview/up CI and production dependency debugging pull the same practices into Ship and Operate. Cloud SDK and stack wiring is integration work—connecting application intent to AWS/Azure/GCP resources—not app frontend or copywriting.
Where it fits
Scaffold a ComponentResource wrapper before adding S3 and Lambda children with explicit parents.
Wire a GitHub Action that fails the PR when pulumi preview shows unexpected replacements.
Add aliases after renaming a bucket resource so production data survives the next up.
How it compares
Opinionated Pulumi program guidance—not a cloud console wizard or a generic DevOps checklist unrelated to Output<T> semantics.
Common Questions / FAQ
Who is pulumi-best-practices for?
Indie builders and small teams maintaining Pulumi TypeScript or Python programs who need predictable previews and safe refactors.
When should I use pulumi-best-practices?
While Build integrations define new cloud resources, during Ship launch when configuring preview/up CI, and in Operate infra when debugging dependency order or apply()-related preview gaps.
Is pulumi-best-practices safe to install?
Review the Security Audits panel on this Prism page; the skill discusses secrets and config patterns but you must still protect stack credentials in your environment.
SKILL.md
READMESKILL.md - Pulumi Best Practices
interface: display_name: "Pulumi Best Practices" short_description: "Best practices for robust Pulumi programs" default_prompt: "Use $pulumi-best-practices to apply reliable Pulumi coding patterns to this task." --- name: pulumi-best-practices version: 1.0.0 description: Load when the user is writing, reviewing, or debugging Pulumi TypeScript/Python programs; asks about Output<T> or apply() usage; wants to create ComponentResource classes; needs to refactor resources without destroying them (aliases); is setting up secrets or config; or is configuring a pulumi preview/up CI workflow. Also load for questions about resource dependency order, parent/child resource relationships, or pulumi.interpolate. --- # Pulumi Best Practices ## When to Use This Skill Invoke this skill when: - Writing new Pulumi programs or components - Reviewing Pulumi code for correctness - Refactoring existing Pulumi infrastructure - Debugging resource dependency issues - Setting up configuration and secrets ## Practices ### 1. Never Create Resources Inside `apply()` **Why**: Resources created inside `apply()` don't appear in `pulumi preview`, making changes unpredictable. Pulumi cannot properly track dependencies, leading to race conditions and deployment failures. **Detection signals**: - `new aws.` or other resource constructors inside `.apply()` callbacks - Resource creation inside `pulumi.all([...]).apply()` - Dynamic resource counts determined at runtime inside apply **Wrong**: ```typescript const bucket = new aws.s3.Bucket("bucket"); bucket.id.apply(bucketId => { // WRONG: This resource won't appear in preview new aws.s3.BucketObject("object", { bucket: bucketId, content: "hello", }); }); ``` **Right**: ```typescript const bucket = new aws.s3.Bucket("bucket"); // Pass the output directly - Pulumi handles the dependency const object = new aws.s3.BucketObject("object", { bucket: bucket.id, // Output<string> works here content: "hello", }); ``` **When apply is appropriate**: - Transforming output values for use in tags, names, or computed strings - Logging or debugging (not resource creation) - Conditional logic that affects resource properties, not resource existence **Reference**: https://www.pulumi.com/docs/concepts/inputs-outputs/ --- ### 2. Pass Outputs Directly as Inputs **Why**: Pulumi builds a directed acyclic graph (DAG) based on input/output relationships. Passing outputs directly ensures correct creation order. Unwrapping values manually breaks the dependency chain, causing resources to deploy in wrong order or reference values that don't exist yet. **Detection signals**: - Variables extracted from `.apply()` used later as resource inputs - `await` on output values outside of apply - String concatenation with outputs instead of `pulumi.interpolate` **Wrong**: ```typescript const vpc = new aws.ec2.Vpc("vpc", { cidrBlock: "10.0.0.0/16" }); // WRONG: Extracting the value breaks the dependency chain let vpcId: string; vpc.id.apply(id => { vpcId = id; }); const subnet = new aws.ec2.Subnet("subnet", { vpcId: vpcId, // May be undefined, no tracked dependency cidrBlock: "10.0.1.0/24", }); ``` **Right**: ```typescript const vpc = new aws.ec2.Vpc("vpc", { cidrBlock: "10.0.0.0/16" }); const subnet = new aws.ec2.Subnet("subnet", { vpcId: vpc.id, // Pass the Output directly cidrBlock: "10.0.1.0/24", }); ``` **For string interpolation**: ```typescript // WRONG const name = bucket.id.apply(id => `prefix-${id}-suffix`); // RIGHT - use pulumi.interpolate for template literals const name = pulumi.interpolate`prefix-${bucket.id}-suffix`; // RIGHT - use pulumi.concat for simple concatenation const name = pulumi.concat("prefix-", bucket.id, "-suffix"); ``` **Reference**: https://www.pulumi.com/docs/concepts/inputs-outputs/ --- ### 3. Use Components for Related Resources **Why**: ComponentResource classes group related resources into reusable, logical units. Withou