Ask most CTOs why their company runs workloads on two or three cloud providers, and the honest answer rarely involves the word decided. It involves the word happened.
An early engineer preferred AWS because the console was friendlier back in 2017. A data team stood up a project in Google Cloud because BigQuery was the obvious choice for the analytics work. Then an acquisition closed, and with it came a whole environment nobody had designed, and an accidental multi-cloud.
Being in multiple clouds is a fact about your infrastructure whereas, going multi-cloud is a decision about your architecture. The first describes where your workloads sit. The second describes why they sit there, on purpose, for a reason you could defend in a board meeting.
Josef Bárta, Chief Architect at Revolgy, describes the pattern from memory:
Usually people end up accidentally in multi-cloud for legacy reasons. There were some early movers in the cloud space, then other cloud providers came, oftentimes providing better service, or even just more user-friendly, easier to get going with, which pulled a lot of people in.
Then the acquisitions start. “A CTO or VP of engineering is a big AWS fan, and all of a sudden you’ve got your main setup nice in Google, and you’ve got your leftovers in AWS. Then before you manage to consolidate it, another acquisition comes, and again a new environment with new vendor lock-in issues. It can be just endless.”
There is a second way to arrive at multiple clouds.
Each of those is a specific, current, defensible reason, and the architecture is built around it from the start.
From a spreadsheet of cloud spend, the two situations look identical. Both show up as “we run on AWS and Google Cloud.” Only one of them is costing you something beyond the invoice.
This piece covers how to tell accidental multi-cloud and designed multi-cloud apart, what to do about the parts with no reason, and how to build the parts that do have a reason so they hold up instead of quietly becoming the next mess.
|
Situation |
Wrong reason |
Right reason |
|
Resilience |
“We should spread risk across providers” as a general instinct, with no load balancing and no tested failover |
Customer-facing workloads load-balanced across two clouds with a tested failover path, because an outage in either is unacceptable to the business |
|
Regulation |
Assuming compliance requires multi-cloud without checking |
A named requirement, such as data residency or a mandated exit strategy from US-based clouds |
|
Cost |
Believing a second cloud is cheaper based on a pricing page rather than your own usage |
A workload with a verified different cost profile on a second provider, measured by running it there |
|
Acquisition |
Leaving an acquired environment untouched because consolidating feels lower priority than the roadmap |
A time-boxed decision to keep it running as-is, with an owner and a review date attached |
|
Product architecture |
Supporting every cloud a prospect might theoretically use, before any customer has asked |
A product customers deploy inside their own infrastructure, where multi-cloud support is a paid-for requirement |
|
Vendor preference |
An engineering leader’s habit carried over from a previous company |
A best-of-breed case, such as Google Cloud for AI and data work specifically because of its vertical integration |
Open a spreadsheet with two columns: the cloud or workload on one side, the reason it’s there on the other. Work through these five questions for every provider and every major workload running on it.
“We don’t know” is a valid entry and the most useful finding this audit produces.
Not “does well.” A team on AWS running BigQuery for analytics has a real answer, because nothing else in their stack offers the same integration between the warehouse and Google’s AI tooling. A stray S3 bucket left over from an acquisition three years ago is an artifact and not a capability. The test is whether removing this cloud would force you to rebuild something, or simply mean deleting something nobody has touched since the migration that never finished.
Imagine an actual page at 3am telling you this account is gone. Is the response “here’s what we lose and here’s why we accepted that risk,” or a scramble to work out what was even running there?
Teams that chose multi-cloud answer this in one sentence, because they made the tradeoff on purpose and wrote it down somewhere, even if that somewhere is a comment in a runbook.
Ownership decays faster than infrastructure. An account set up by an engineer who left eighteen months ago, inherited by whoever had admin access at the time, signals an accidental setup regardless of how well it currently runs.
A cloud with a current owner stays intentional, because someone is accountable for justifying it at every budget review. A cloud with no owner just persists.
This catches retroactive justification. “We’re multi-cloud for resilience” holds up if it was the reason from the start, with a load balancer and a failover plan built around it. It holds up much less if it’s being invoked for the first time in response to this audit, three years after an acquisition put the workload there.
The architecture tells the truth even when the explanation doesn’t.
Engineering time spent context-switching between consoles and IaC dialects. A security review that now covers a second identity model. An on-call engineer holding two sets of alerting conventions. Spend and performance visibility split across two dashboards. None of it appears on a cost report, but all of it appears in how slow the team feels six months later.
Every row ends up in one of two buckets: a documented, current reason, or no reason found. That split is the input for everything below.
The instinct to consolidate everything immediately costs almost as much as the instinct to never touch it. Run each no-reason item through this sequence.
Some items migrate, some get a documented decision to stay, and a few turn out to have a reason the audit missed. That last group joins the next section.
Plenty of companies with a defensible reason for two clouds still end up with the same operational mess as the accidental case. Because the execution is not planned. Here are the best practices to make it happen:
Terraform should define every resource across every cloud you deliberately run. The code will not look the same across providers, and forcing identical modules across different services creates its own mess. What matters is that nothing exists only as a manual console change living in one engineer’s memory.
As Josef puts it: “You will be writing a different Terraform for Google, different Terraform for AWS. It’s the software that’s the difficult bit.” The infrastructure layer is where clouds are allowed to look different. The layer above it needs discipline.
Container-based compute like Cloud Run carries little lock-in, because the thing inside the container doesn’t care which cloud schedules it. A provider-specific serverless model built tightly around one event system buys actual capability and makes portability much harder to claim later. The mistake is claiming the portability of the first while building the second, and discovering the difference when you try to move something.
Compute is portable in a way data rarely is. SQL databases scale vertically well and horizontally poorly, so there will always be a single authoritative instance handling writes no matter how many clouds you span. The workable pattern is a primary in one cloud with read replicas or a standby in the other, and a tested failover procedure. Be honest about what that failover looks like.
Josef says:
It’s never going to be completely seamless. You can play around with caches, degrade the service instead of taking it down completely, but it’s still a little bit of a jolt.
Plan for that jolt through graceful degradation and caching, rather than promising a clean cutover the database can’t deliver.
Deliverable at day 20: A confidence-scored inventory with every account and major workload marked “documented reason” or “no reason found,” an owner on every row, and a short list of genuinely unresolved items.
Deliverable at day 60: Every no-reason item has a decision and an owner, the low-risk migrations are done or moving, and the rest have decided dates.
Deliverable at day 90: A documented estate with IaC covering every workload, a tested failover path, unified cross-cloud visibility, and a governance process that catches the next accidental cloud early.
Ninety days is not enough time to migrate everything, and it doesn’t need to be. It is enough to replace a drifting cloud footprint with one where every part has an owner, a reason, and a review date.
An external architect has no stake in whether a cloud’s reason holds up, no relationship to protect with the engineer who made the call, and no instinct to be generous to a decision made on their own watch.
Revolgy has run this process across customers on all ends:
Revolgy runs free 45-minute 1:1 working sessions with senior architects. Bring the audit spreadsheet, even half-finished, or bring the one cloud account you can’t yet explain. Within 24 hours of the session, you receive a structured summary of the gaps identified and the recommended next steps.
Check whether you can name a specific, current business reason for each provider, along with a clear owner accountable for that reason. The absence of a documented reason and a named owner, rather than the fact of running more than one cloud, is what signals an accidental setup.
Only where no active business or regulatory reason exists for the extra provider. And only after pricing the overhead of keeping it against the total cost of migrating away. This is a workload-by-workload decision, not a one-size-fits-all decision.
Not in the way many teams assume. SQL databases require a single authoritative instance handling writes regardless of how many clouds you use, so a genuine multi-cloud data setup means a primary in one location with read replicas or a standby elsewhere, plus a tested failover procedure.
No. Omni runs BigQuery’s compute inside your existing AWS or Azure environment to query data where it already lives, which is a cost and egress optimization. Your authoritative data strategy should be decided separately from whether you use it.