$npx -y skills add pulumi/agent-skills --skill pulumi-automation-apiLoad this skill when a user asks how to run Pulumi programmatically, embed Pulumi in an application, orchestrate multiple stacks in code, build a self-service infrastructure portal, replace pulumi CLI shell scripts with code, or use the Pulumi Automation API (LocalWorkspace, crea
| 1 | # Pulumi Automation API |
| 2 | |
| 3 | ## When to Use This Skill |
| 4 | |
| 5 | Invoke this skill when: |
| 6 | |
| 7 | - Orchestrating deployments across multiple Pulumi stacks |
| 8 | - Embedding Pulumi operations in custom applications |
| 9 | - Building self-service infrastructure platforms |
| 10 | - Replacing fragile Bash/Makefile orchestration scripts |
| 11 | - Creating custom CLIs for infrastructure management |
| 12 | - Building web applications that provision infrastructure |
| 13 | |
| 14 | ## What is Automation API |
| 15 | |
| 16 | Automation API provides programmatic access to Pulumi operations. Instead of running `pulumi up` from the CLI, you call functions in your code that perform the same operations. |
| 17 | |
| 18 | ```typescript |
| 19 | import * as automation from "@pulumi/pulumi/automation"; |
| 20 | |
| 21 | // Create or select a stack |
| 22 | const stack = await automation.LocalWorkspace.createOrSelectStack({ |
| 23 | stackName: "dev", |
| 24 | projectName: "my-project", |
| 25 | program: async () => { |
| 26 | // Your Pulumi program here |
| 27 | }, |
| 28 | }); |
| 29 | |
| 30 | // Run pulumi up programmatically |
| 31 | const upResult = await stack.up({ onOutput: console.log }); |
| 32 | console.log(`Update summary: ${JSON.stringify(upResult.summary)}`); |
| 33 | ``` |
| 34 | |
| 35 | ## When to Use Automation API |
| 36 | |
| 37 | ### Good Use Cases |
| 38 | |
| 39 | **Multi-stack orchestration:** |
| 40 | |
| 41 | When you split infrastructure into multiple focused projects, Automation API helps offset the added complexity by orchestrating operations across stacks: |
| 42 | |
| 43 | ```text |
| 44 | infrastructure → platform → application |
| 45 | ↓ ↓ ↓ |
| 46 | (VPC) (Kubernetes) (Services) |
| 47 | ``` |
| 48 | |
| 49 | Automation API ensures correct sequencing without manual intervention. |
| 50 | |
| 51 | **Self-service platforms:** |
| 52 | |
| 53 | Build internal tools where developers request infrastructure without learning Pulumi: |
| 54 | |
| 55 | - Web portals for environment provisioning |
| 56 | - Slack bots that create/destroy resources |
| 57 | - Custom CLIs tailored to your organization |
| 58 | |
| 59 | **Embedded infrastructure:** |
| 60 | |
| 61 | Applications that provision their own infrastructure: |
| 62 | |
| 63 | - SaaS platforms creating per-tenant resources |
| 64 | - Testing frameworks spinning up test environments |
| 65 | - CI/CD systems with dynamic infrastructure needs |
| 66 | |
| 67 | **Replacing fragile scripts:** |
| 68 | |
| 69 | If you have Bash scripts or Makefiles stitching together multiple `pulumi` commands, Automation API provides: |
| 70 | |
| 71 | - Proper error handling |
| 72 | - Type safety |
| 73 | - Programmatic access to outputs |
| 74 | |
| 75 | ### When NOT to Use |
| 76 | |
| 77 | - Single project with standard deployment needs |
| 78 | - When you don't need programmatic control over operations |
| 79 | |
| 80 | ## Architecture Choices |
| 81 | |
| 82 | ### Local Source vs Inline Source |
| 83 | |
| 84 | **Local Source** - Pulumi program in separate files: |
| 85 | |
| 86 | ```typescript |
| 87 | const stack = await automation.LocalWorkspace.createOrSelectStack({ |
| 88 | stackName: "dev", |
| 89 | workDir: "./infrastructure", // Points to existing Pulumi project |
| 90 | }); |
| 91 | ``` |
| 92 | |
| 93 | **When to use:** |
| 94 | |
| 95 | - Different teams maintain orchestrator vs Pulumi programs |
| 96 | - Pulumi programs already exist |
| 97 | - Want independent version control and release cycles |
| 98 | - Platform team orchestrating application team's infrastructure |
| 99 | |
| 100 | **Inline Source** - Pulumi program embedded in orchestrator: |
| 101 | |
| 102 | ```typescript |
| 103 | import * as aws from "@pulumi/aws"; |
| 104 | |
| 105 | const stack = await automation.LocalWorkspace.createOrSelectStack({ |
| 106 | stackName: "dev", |
| 107 | projectName: "my-project", |
| 108 | program: async () => { |
| 109 | const bucket = new aws.s3.Bucket("my-bucket"); |
| 110 | return { bucketName: bucket.id }; |
| 111 | }, |
| 112 | }); |
| 113 | ``` |
| 114 | |
| 115 | **When to use:** |
| 116 | |
| 117 | - Single team owns everything |
| 118 | - Tight coupling between orchestration and infrastructure is desired |
| 119 | - Distributing as compiled binary (no source files needed) |
| 120 | - Simpler deployment artifact |
| 121 | |
| 122 | ### Language Independence |
| 123 | |
| 124 | The Automation API program can use a different language than the Pulumi programs it orchestrates: |
| 125 | |
| 126 | ```text |
| 127 | Orchestrator (Go) → manages → Pulumi Program (TypeScript) |
| 128 | ``` |
| 129 | |
| 130 | This enables platform teams to use their preferred language while application teams use theirs. |
| 131 | |
| 132 | ## Common Patterns |
| 133 | |
| 134 | ### Multi-Stack Orchestration |
| 135 | |
| 136 | Deploy multiple stacks in dependency order: |
| 137 | |
| 138 | ```typescript |
| 139 | import * as automation from "@pulumi/pulumi/automation"; |
| 140 | |
| 141 | async function deploy() { |
| 142 | const stacks = [ |
| 143 | { name: "infrastructure", dir: "./infra" }, |
| 144 | { name: "platform", dir: "./platform" }, |
| 145 | { name: "application", dir: "./app" }, |
| 146 | ]; |
| 147 | |
| 148 | for (const stackInfo of stacks) { |
| 149 | console.log(`Deploying ${stackInfo.name}...`); |
| 150 | |
| 151 | const stack = await automation.LocalWorkspace.createOrSelectStack({ |
| 152 | stackName: "prod", |
| 153 | workDir: stackInfo.dir, |
| 154 | }); |
| 155 | |
| 156 | await stack.up({ onOutput: console.log }); |
| 157 | console.log(`${stackInfo.name} deployed successfully`); |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | async function des |