Skip to content
Notifications
Clear all

Thoughts on Pulumi YAML for simple stacks? Tried it for a migration prototype.

3 Posts
3 Users
0 Reactions
10 Views
(@alexg)
Honorable Member
Joined: 3 months ago
Posts: 564
Topic starter   [#26069]

I've been evaluating Pulumi YAML as a potential path for migrating a subset of our simpler, non-production stacks away from a legacy CloudFormation setup. The promise is compelling: a declarative YAML interface with access to the full Pulumi resource model and engine, ostensibly without the need to write TypeScript or Python. After building a prototype for a straightforward AWS VPC and RDS stack, I have some concrete observations that I believe are worth discussing, particularly for those considering a similar migration.

The initial appeal is undeniable for migration scenarios. The YAML structure maps cleanly from CloudFormation or Terraform HCL, and the ability to reference any Pulumi provider resource is a significant advantage over being locked into a single vendor's DSL. For example, defining an AWS Security Group is syntactically straightforward:

```yaml
resources:
appSecurityGroup:
type: aws:ec2:SecurityGroup
properties:
vpcId: ${vpc.id}
description: "Application security group"
ingress:
- protocol: tcp
fromPort: 443
toPort: 443
cidrBlocks: ["0.0.0.0/0"]
```

However, the abstraction begins to show cracks when you move beyond trivial property assignment. The moment you need any form of transformation, string manipulation, or conditional logic, you are forced into Pulumi's YAML expression syntax. This syntax, while powerful, becomes a labyrinthine mix of function calls like `toJSON` and `invoke` that negates the readability YAML is supposed to provide. You essentially trade one domain-specific language (HCL) for another, more awkward one embedded within YAML strings. My prototype required a loop to create multiple subnets, and the resulting YAML was far less maintainable than the equivalent in Pulumi's imperative languages.

Furthermore, the tooling and ecosystem feel secondary. The feedback loop is slower. Error messages from the engine are often nested and refer to the generated Pulumi program, not your YAML source, making debugging an exercise in translation. For a migration, this is a critical pain point—state import operations are already fraught, and opaque errors compound the risk.

My preliminary conclusion is that Pulumi YAML serves a very narrow niche: truly static, declarative stacks where resources are defined purely by their direct properties. For any migration of complexity, the investment in learning the expression syntax and debugging model likely outweighs the initial familiarity benefit. I'm now leaning towards the opinion that using a general-purpose language like TypeScript with Pulumi, despite the initial learning curve, provides superior long-term maintainability, refactoring capabilities, and developer experience, even for "simple" stacks.

I'm interested to hear from others who have gone further down this path. Has anyone successfully completed a migration using Pulumi YAML for more than a dozen resources? Did you hit a complexity wall, and if so, how did you address it? Conversely, are there patterns or tooling I've missed that make the expression syntax manageable?

-- alex



   
Quote
(@brookel)
Estimable Member
Joined: 3 months ago
Posts: 169
 

I've been considering Pulumi YAML for some side-project stuff too. That mapping from CloudFormation/Terraform you mentioned is exactly what caught my eye for moving some old configs.

But I'm already nervous about where those "cracks" start to show. Can you give a quick example? Like, does it get messy when you need to add a simple function or loop, or is it something else? Trying to figure out if it's worth the time for my little homelab stacks.


Self-host or die trying.


   
ReplyQuote
(@claraj)
Reputable Member
Joined: 3 months ago
Posts: 342
 

Exactly. The initial mapping is neat until you need anything remotely dynamic. Your security group example is trivial. Try referencing an output from another stack, or constructing a name with a timestamp. Suddenly you're deep in Pulumi's expression syntax, which is just a weird YAML-embedded language. It's the worst of both worlds: none of the simplicity of plain config, and none of the power of a real language.

The vendors love pushing these "simple" interfaces because they lock you in without giving you real flexibility. Once you hit a limitation, you're stuck.


Prove it


   
ReplyQuote