At least once a quarter, a prospective client tells me their architecture needs to be multi-cloud. When I ask why, the answer is almost always some version of "to avoid vendor lock-in". When I ask what specifically they're afraid the vendor will do, the conversation gets vague. And when I look at what they're actually running, one cloud, plus a half-maintained beachhead in another that exists mostly in slide decks, the pattern completes itself.

I want to be precise here, because "multi-cloud is bad" is as lazy as "multi-cloud is strategic". Multi-cloud is a cost. Sometimes it's a cost worth paying. Most of the time, for most companies, it's a tax paid on an insurance policy that doesn't cover the risk you think it covers.

The real drivers versus the imagined one

In the engagements I've seen, genuine multi-cloud has three honest origins:

Regulation and data sovereignty. A regulator, or a large customer's procurement department, requires data in a jurisdiction or on infrastructure your primary cloud doesn't serve well. This is real. You don't get to argue with the central bank.

Acquisition. Company A on AWS buys company B on Azure. Congratulations, you are now multi-cloud, not by strategy but by paperwork. The honest framing is that this is a migration project with an indefinite timeline, not an architecture.

A specific, superior service. You're an AWS shop but the ML team genuinely needs something GCP does better, or your data warehouse story is simply better on BigQuery. Fine, if it's scoped as "this workload lives there", not "we are cloud-agnostic now".

And then there's the imagined driver: portability as leverage. The theory says that being able to leave AWS gives you negotiating power and protects you from price hikes. In practice I have never met a mid-sized company that executed the threat, and the vendors know it. Real egress of a serious platform is a multi-year project; a discount conversation happens annually. The negotiating leverage that actually works is commitment, EDP-style agreements, reserved capacity, growth, which is the opposite of keeping one foot out the door. You get better pricing by marrying the vendor, not by conspicuously dating their competitor.

What the tax actually costs

The costs of multi-cloud are systematically underestimated because the biggest ones don't appear on the cloud bill.

Double expertise. Your team must now be good at two IAM models, two networking stacks, two sets of failure modes, two security baselines, two sets of quotas and their sharp edges. An engineer who is excellent at AWS and mediocre at Azure is, on the Azure side, a liability with confidence. For a large enterprise, you hire two platform teams. For everyone else, you get one team that's mediocre at both, and mediocrity in cloud platforms expresses itself as security incidents and outages.

Lowest-common-denominator architecture. The moment "must run on both clouds" becomes a design constraint, you forfeit the best parts of each. No DynamoDB, no Aurora, no BigQuery, no EventBridge, nothing that doesn't have a twin on the other side. You end up running everything on VMs and Kubernetes and self-managed open source, which means you've paid premium cloud prices to rebuild a datacenter, and taken on the operational load of every stateful system your cloud would have managed for you. The managed services are the value proposition. Architecting to avoid them is paying for a restaurant and bringing your own sandwiches.

Egress. Data transfer between clouds is priced like the vendors don't want you to do it, because they don't. Any architecture with a chatty path between clouds, replication, service calls, a data pipeline, accrues a permanent, growing line item. One client's "resilient" cross-cloud replication design would have cost more in egress annually than the projected downtime it protected against, in the worst year we could model.

Tooling and process duplication. CI/CD, monitoring, incident response, cost management, compliance evidence, all of it forks. Every audit takes twice as long. Every new hire's onboarding covers twice the surface.

Where it genuinely makes sense

To be fair to the other side, I have recommended multi-cloud, in specific shapes:

  • Regulated isolation: separate workloads in separate clouds for jurisdictional reasons, with essentially no traffic between them. The tax is low because the clouds don't need to talk.
  • Best-of-breed islands: the scoped "this one workload lives on GCP because BigQuery" pattern, with a clean, batchy, well-understood data interface between the islands.
  • Post-acquisition reality: run both competently while migrating deliberately, rather than pretending the combined estate is a strategy.
  • Genuine scale: if your cloud bill has enough digits that a percentage point of negotiated discount funds a platform team, the calculus changes. You know who you are, and you're not reading a consultant's blog for this decision.

Notice what all the healthy shapes share: minimal cross-cloud coupling. Multi-cloud works as an archipelago. It fails as a mesh.

"Portable enough": the honest middle

Rejecting reflexive multi-cloud doesn't mean welding yourself to the vendor at every layer. There's a cheap, sane level of portability I'd recommend to anyone, not because you'll switch clouds, but because the same practices are just good engineering:

  • Containers for your own code. Your applications shouldn't care whose VMs they run on. This costs nothing extra; it's how you should build anyway.
  • Terraform (or OpenTofu) for everything. Not because HCL is portable, an AWS module is useless on Azure, but because your infrastructure being declared, reviewed, and reproducible is what makes any future migration a project instead of an archaeology dig.
  • Open standards at the interfaces. Postgres-compatible over proprietary wire protocols, S3-compatible object APIs, OpenTelemetry for observability, OIDC for identity. Prefer the option with an exit ramp when the cost of preferring it is small.
  • Isolate the proprietary edges. When you do use DynamoDB or SQS, and you should, if they fit, keep the SDK calls behind your own thin interfaces rather than letting them soak through the codebase. Standard hexagonal-architecture hygiene, useful for testing anyway.

And then stop pretending the rest is avoidable. Your IAM policies, your networking design, your operational knowledge, your team's scar tissue, all of it is lock-in, and no abstraction layer removes it. Kubernetes doesn't make you portable; it makes your compute portable while your identity, data gravity, and managed services stay put. Lock-in isn't a binary you escape. It's a dial, and every notch toward "portable" has a price tag. The only sane approach is to pay for portability exactly where it's cheap, and consciously accept lock-in where the managed service earns it.

Pick one cloud. Go deep. Use the good parts, that's what you're paying for. Keep your code containerised, your infrastructure declared, and your interfaces clean, so that if the improbable day comes, you're facing an expensive project rather than an impossible one. That's not vendor lock-in. That's just choosing where to spend your complexity budget, and multi-cloud, for most teams, spends it on insurance against the wrong risk.