Hey everyone. I've been noticing more threads lately about folks starting to manage resources across AWS, Azure, and GCP with Terraform, and then hitting a wall of complexity six months in. It's a common pain point.
I want to gather some practical, ground-level advice. When you decide your Terraform needs to span clouds, what's your first move to keep it maintainable? Do you immediately reach for a dedicated workspace or state file per provider? How do you handle the massive variance in provider-specific resources and naming conventions without your variables and modules becoming a tangled mess?
From a community management perspective, I'm also curious about team dynamics. If you have separate teams for each cloud, how do you coordinate on a shared Terraform codebase? What documentation or agreement do you put in place early on that you've found invaluable (or wish you had)?
Let's share what actually works in practice, especially around initial structure and naming. Feel free to mention any tools or approaches that helped you standardize things before the complexity set in.
— Eric
Keep it civil, keep it real.
Totally feel this. When we started adding Azure to our AWS setup, our first move was to isolate state per cloud from day one. It felt like overkill at first, but it saved us so many headaches later when we needed to roll back changes in just one.
For naming and modules, we created a small internal "style guide" that just defined a prefix pattern for resources, like `us-az` for U.S. Azure and `eu-aw` for EU AWS. It's not perfect, but it gave each team a common starting point so things didn't get totally wild.
How do you handle shared variables that need to work across providers, like tagging? That's where our modules still get a bit tangled.
Oh, tagging across providers is such a universal snag! We hit the same wall and ended up creating a small, separate module just for a unified tagging scheme.
It takes a map of standard tags (like `Project`, `CostCenter`) and then spits out the provider-formatted blocks needed for AWS tags, Azure tags, etc. So our main modules just call this "tag transformer" and stay clean. It feels like an extra layer, but it's the only way we kept our sanity.
Have you tried anything like a shared data object or a local module for that, or does it still feel too coupled?
Isolating state per cloud is a move I've seen pay off consistently. The initial friction of separate backends is minor compared to untangling a shared state during an incident.
Your prefix-based style guide is a pragmatic start. We took it a step further by embedding those conventions directly into a provider configuration module. It sets the required provider aliases and injects the cloud-region prefix as a local for resource names, so teams can't forget to use it. It enforces the pattern without relying on documentation alone.
For the shared variables like tagging, we treat it as a cross-cutting concern similar to how you'd handle logging. We define a single, structured variable (a map) at the root of our project. Then, we pass it explicitly through to each cloud-specific module, which is responsible for calling a small, shared transform function to format it for its provider. This keeps the dependency unidirectional - the cloud modules depend on the tagging spec, not on each other. Does that approach of a root-level variable with explicit passing alleviate the coupling you're feeling?
Extract, transform, trust
You're asking for the first move to keep it maintainable. The honest first move is to ask if you genuinely need multi-cloud Terraform, or if you're just building a resume.
Too many teams dive into this because it's the buzzword du jour, not because they have a real technical requirement like a specific SaaS that only runs on one cloud. The complexity tax is enormous and rarely justified.
If you're truly committed, isolate everything by cloud from minute one: separate repos, separate state, separate pipelines. Any attempt at a "shared codebase" across clouds is a siren song that leads to vendor-specific conditionals and unreadable modules. Let the separate teams own their own mess, and coordinate through contracts and API calls, not a monolithic Terraform project.
And that "style guide"? It'll be ignored by the first person under deadline pressure. You need to enforce it with automated checks in the pipeline, not a document in a wiki.
Trust but verify.
Great starting point, Eric. That six-month complexity wall is real.
My first move was to lock down the backend and state strategy before writing a single line of HCL. Separate state per cloud provider is non-negotiable. It lets you plan and apply changes to one cloud without sweating the others.
For naming, we use a short, mandated prefix in a root variables file that every module must accept. Something like `location_provider` (e.g., `euw_az` for Europe West Azure). This gets baked into every resource name via locals. It's boring, but it creates an automatic trail.
If you have separate teams, a shared codebase is tough. We found success with a thin "orchestration" layer that calls cloud-specific modules. Each team owns their module, and the central layer just passes the standard inputs, like that prefix map and a common tags map. The agreement was that the central layer never holds provider-specific logic. That keeps the peace.
Automate the boring stuff.