Blog

Why a generic multi-cloud form quietly breaks multi-cloud Terraform

A form that works the same way for AWS, Azure, and GCP is hiding the fact that those three providers don't agree on what a disk, a region, or a network even is.

· 6 min read

The abstraction that seems like a shortcut

Most multi-cloud tools converge on the same idea: one form, one set of fields — instance size, region, disk, network — mapped onto whichever provider you pick. It reads as a feature. Fewer fields to learn, one mental model across 12 providers.

It's also where multi-cloud Terraform quietly starts to drift from what the provider actually supports. AWS, Azure, and GCP don't agree on what a "region" is scoped to, what a disk's performance tier options are, or which network attributes are mandatory versus inferred. A generic field forces all three into the same shape — and the parts that don't fit get silently dropped or defaulted, not surfaced.

Where the lowest common denominator shows up later

This doesn't fail at generation time. The form is easy to fill in, the file plans, the demo works. It shows up three ways later:

Attributes you needed aren't in the form, because the form only exposes what's common across all providers, not what's specific to the one you're actually using. You end up hand-editing the generated file to add the provider-specific attribute — which reintroduces exactly the maintenance burden a wizard was supposed to remove.

Defaults get picked for you, silently, for anything the generic schema didn't ask about. On a provider where that default is expensive or insecure, you don't find out until a bill or a security review flags it.

Switching providers isn't actually simple, even though the generic form implies it should be. The fields matched syntactically, not semantically — a "machine size" field on AWS and the equivalent on GCP don't round-trip cleanly, because the underlying resource types were never the same shape to begin with.

A schema per provider, not a schema for the lowest common denominator

NebulaStack's multi-provider wizard is built the other way: every provider has its own wizard exposing real Terraform resource attributes for that provider, field for field — not a stripped-down form shared across all 12. It feeds the same typed-intent pipeline as the AI assistant, so a request made through the AWS wizard and a request made through the AI chat produce output through the same deterministic emitter.

That emitter is what actually multi-cloud consistency depends on. Terraform, Pulumi, and Crossplane are generated production-grade across all 12 supported providers by a deterministic code generator — not the language model — precisely so that "multi-cloud" doesn't mean "the same brittle abstraction copy-pasted across three provider blocks." Kubernetes workloads get their own manifests, Helm charts, and Kustomize overlays rather than being squeezed into the same VM-shaped form as a cloud instance.

The trade-off is real: a dedicated wizard per provider means more surface area to build and maintain than one generic form. It's the trade-off worth making, because the alternative — one shape for every provider — isn't actually simpler. It's the same complexity, deferred to the moment you discover what the generic form left out.

Describe. Review. Apply.

Free to start, no credit card.