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:
Right:
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 awaiton output values outside of apply- String concatenation with outputs instead of
pulumi.interpolate
Wrong:
Right:
For string interpolation:
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. Without components, your resource graph is flat, making it hard to understand which resources belong together, reuse patterns across stacks, or reason about your infrastructure at a higher level.
Detection signals:
- Multiple related resources created at top level without grouping
- Repeated resource patterns across stacks that should be abstracted
- Hard to understand resource relationships from the Pulumi console
Wrong:
Right:
Component best practices:
- Use a consistent type URN pattern:
organization:module:ComponentName - Call
registerOutputs()at the end of the constructor - Expose outputs as class properties for consumers
- Accept
ComponentResourceOptionsto allow callers to set providers, aliases, etc.
For in-depth component authoring guidance (args design, multi-language support, testing, distribution), use skill pulumi-component.
Reference: https://www.pulumi.com/docs/concepts/resources/components/
4. Always Set parent: this in Components
Why: When you create resources inside a ComponentResource without setting parent: this, those resources appear at the root level of your stack's state. This breaks the logical hierarchy, makes the Pulumi console hard to navigate, and can cause issues with aliases and refactoring. The parent relationship is what makes the component actually group its children.
Detection signals:
- ComponentResource classes that don't pass
{ parent: this }to child resources - Resources inside a component appearing at root level in the console
- Unexpected behavior when adding aliases to components
Wrong:
Right:
What parent: this provides:
- Resources appear nested under the component in Pulumi console
- Deleting the component deletes all children
- Aliases on the component automatically apply to children
- Clear ownership in state files
Reference: https://www.pulumi.com/docs/concepts/resources/components/
5. Encrypt Secrets from Day One
Why: Secrets marked with --secret are encrypted in state files, masked in CLI output, and tracked through transformations. Starting with plaintext config and converting later requires credential rotation, reference updates, and audit of leaked values in logs and state history.
Detection signals:
- Passwords, API keys, tokens stored as plain config
- Connection strings with embedded credentials
- Private keys or certificates in plaintext
Wrong:
Right:
In code:
Use Pulumi ESC for centralized secrets:
What qualifies as a secret:
- Passwords and passphrases
- API keys and tokens
- Private keys and certificates
- Connection strings with credentials
- OAuth client secrets
- Encryption keys
References:
6. Use Aliases When Refactoring
Why: Renaming resources, moving them into components, or changing parents causes Pulumi to see them as new resources. Without aliases, refactoring destroys and recreates resources, potentially causing downtime or data loss. Aliases preserve resource identity through refactors.
Detection signals:
- Resource rename without alias
- Moving resource into or out of a ComponentResource
- Changing the parent of a resource
- Preview shows delete+create when update was intended
Wrong:
Right:
Moving into a component:
Alias types:
Lifecycle:
- Add alias during refactor
- Run
pulumi upon all stacks - Remove alias after all stacks updated (optional, but keeps code clean)
Reference: https://www.pulumi.com/docs/iac/concepts/resources/options/aliases/
7. Preview Before Every Deployment
Why: pulumi preview shows exactly what will be created, updated, or destroyed. Surprises in production come from skipping preview. A resource showing "replace" when you expected "update" means imminent destruction and recreation.
Detection signals:
- Running
pulumi up --yesinteractively without reviewing changes - No preview step anywhere in the CI/CD workflow for a given change
- Preview output not reviewed before merge or deployment approval
Wrong:
Right:
What to look for in preview:
+ create- New resource will be created~ update- Existing resource will be modified in place- delete- Resource will be destroyed+-replace- Resource will be destroyed and recreated (potential downtime)~+-replace- Resource will be updated, then replaced
Warning signs:
- Unexpected
replaceoperations (check for immutable property changes) - Resources being deleted that shouldn't be
- More changes than expected from your code diff
CI/CD integration:
PR workflow:
- Run preview on every PR
- Post preview output as PR comment
- Require preview review before merge
- Deploy only on merge to main
References:
- https://www.pulumi.com/docs/cli/commands/pulumi_preview/
- https://www.pulumi.com/docs/iac/packages-and-automation/continuous-delivery/github-actions/
Quick Reference
Validation Checklist
When reviewing Pulumi code, verify:
- No resource constructors inside
apply()callbacks - Outputs passed directly to dependent resources
- Related resources grouped in ComponentResource classes
- Child resources have
{ parent: this } - Sensitive values use
config.requireSecret()or--secret - Refactored resources have aliases preserving identity
- Deployment process includes preview step
Related Skills
- pulumi-overview: Entry-point skill that orients an agent across the three Pulumi surfaces (
pulumi doCLI, IaC projects, and Pulumi Cloud) and routes to specialized skills. Load it first when the task begins with general infrastructure phrasing or spans multiple Pulumi surfaces. Use skillpulumi-overview. - pulumi-component: Deep guide to authoring ComponentResource classes, designing args interfaces, multi-language support, testing, and distribution. Use skill
pulumi-component. - pulumi-automation-api: Programmatic orchestration of multiple stacks. Use skill
pulumi-automation-api. - pulumi-esc: Centralized secrets and configuration management. Use skill
pulumi-esc.


