Let’s talk about the promised land of “infrastructure as code” and the stark reality that not all constructs are created equal. I’ve spent the last three years rotating through Terraform, Pulumi, and now CDK, chasing that elusive combination of developer experience and operational stability. My latest experiment? Evaluating the construct library maturity across the big three clouds using AWS CDK, CDK for Terraform (cdktf), and the respective Azure/Google providers.
The core hypothesis, which I held with naive optimism, was that by 2024, the abstraction would be complete. I could define a serverless function with associated queue, monitoring, and IAM in ten lines of clean code, and it would Just Work across clouds. The reality is a landscape of jagged peaks and deep valleys.
Here’s the blunt assessment, based on migrating a fairly standard serverless event-driven pipeline pattern across each provider:
* **AWS CDK:** The baseline. Constructs are numerous and, for the most common patterns, polished. Want an SQS-triggered Lambda with a dead-letter queue, CloudWatch alarms, and custom IAM permissions? `aws-lambda-event-sources` and `aws-lambda` have you covered. The devil is in the escape hatches – you will still need to drop to raw CloudFormation for anything remotely novel, and the “blessed” constructs sometimes feel like a veneer over the sheer chaos of CFN resource specs. Maturity: high, but with a ceiling of complexity they can’t fully abstract.
* **Azure (via cdktf):** A study in inconsistency. The `@cdktf/provider-azurerm` modules are a direct mapping of Terraform resources, so you’re essentially writing Terraform in TypeScript. The “construct” concept here is largely DIY. Want a similar Function App + Storage Queue + Monitoring setup? You’re manually wiring a dozen disparate resources, each with its own idiosyncratic property schema. There is no equivalent of the AWS “event-source” construct; you’re piecing together the event subscription, the identity, the networking. Library maturity feels like a thin wrapper over the ARM template chaos, with none of the high-level design AWS has attempted.
* **GCP (via cdktf or CDKTF’s GCP provider):** Surprisingly coherent for core services, but sparse. The pattern library is minimal. For my pipeline, I found a `google_cloudfunctions_function` resource but the event integration for Pub/Sub was manual configuration. The IAM model is different enough that any attempt at a cross-cloud abstraction layer I built immediately sprang leaks. The constructs feel closer to the metal, which is fine if you want control, but it defeats the “high-level abstraction” promise of CDK.
The migration pain points were entirely predictable:
* State import was the least of my worries; it’s a one-time brute-force exercise.
* The refactoring effort, however, was essentially a ground-up rewrite. A “queue processor” is not a universal concept across these libraries. The cognitive load shifted from “how do I compose my constructs?” to “how does this cloud’s resource model even work?”, which is exactly what CDK was supposed to mitigate.
* Was it worth it? For a greenfield project locked to one cloud, AWS CDK is the clear leader. Attempting a multi-cloud strategy with CDK abstractions today is a fast track to building your own, poorly documented, framework.
So, my question to those who’ve done the same walk of shame: have you found any third-party construct libraries for Azure or GCP that approach the cohesiveness of AWS’s offerings? Or is the only sane approach to embrace the lowest common denominator and stick to raw Terraform modules across all three, sacrificing developer experience for consistency?