This is the third post in my Typescript/Infrastructure-as-code (IaC) series. Part I (technical) and Part II (organizational).

Historically, this is how I've looked at the application stack. I'll call this The Configuration Stack.

As you move up the stack, there's less configuration and less infrastructure – but the solution space is constrained. At the very top, specific flavors of code (constrained by framework, language, etc.), no configuration. At the very bottom, code agnostic configuration. The layers aren't incredibly coupled, but are very cognizant of the the layer above and layer below. Layers are rigid. And of course, this is a spectrum, so the examples are loosely sorted and non-exhaustive.

But infrastructure as code has its own emerging stack. I'll call this the parallel Compiled Infrastructure Stack.

Since the compiled infrastructure stack is all code, there's transpilation between competing layers, compilers down the stack, and eventually everything gets compiled to call the cloud APIs. It's parallel to the configuration stack because they are essentially fulfilling the same need (managing infrastructure) for the same two sets of users (developers and operations engineers). It's much easier to move up and down the layers in the compiled infrastructure stack.

The most surprising (but obvious in hindsight) takeaway is that the most natural layer of infrastructure as code isn't for operations. It's for developers.

In the future, I wouldn't be surprised to see the ??? filled in by a infrastructure-as-code framework – opinionated high level service templates like new VercelService(this, { ... } ) or new StaticCDNSite('', { ... }. Managed services would simply be templates. As high level as needed, with an escape hatch to the layer below (Pulumi/CDK) when needed.