Ask an engineering organisation whether it is multi-cloud and the answer is usually yes. Ask when the decision was made and almost nobody can name a meeting. The second provider arrived with an acquisition, or with the analytics team's warehouse, or with the one vendor whose product only ships into one cloud. That distinction — between multi-cloud that was decided and multi-cloud that accumulated — matters more than any of the arguments usually made for it, because the two produce completely different bills and completely different failure modes.
Most multi-cloud arrived, it was not chosen
The accidental paths are worth naming because each has a different half-life. An acquisition hands you a running estate with its own accounts, its own network ranges, its own on-call rota and a team that knows one provider well and yours not at all. That is multi-cloud for as long as the integration programme takes, which is always longer than the slide said, and sometimes forever because the revenue does not justify the rewrite.
A single SaaS or managed vendor that only sells into one provider drags a footprint behind it: a private endpoint, a peering, a service account, a bucket the vendor writes into, a set of firewall exceptions. Nobody calls this a cloud strategy, but it creates the same identity, network and compliance obligations as one.
Shadow adoption is the third path. A data science group opens an account on a corporate card because the model they want is only available there, and eighteen months later it holds production features. The tell is always the same: the account exists in the invoice before it exists in the inventory.
None of these were arguments about lock-in or resilience. Yet they are, in practice, what most multi-cloud is. The useful first question in any review is therefore not "should we be multi-cloud" but "which of our providers did we choose, and which did we inherit?" The inherited ones deserve an explicit decision: absorb, isolate, or exit. Leaving them undecided is how an organisation ends up paying the operating cost of a strategy it never adopted.
The five reasons given, and which ones survive contact
Strategic multi-cloud is argued from a short and stable list. They are not equally good arguments, and the differences are worth being blunt about.
| Motivation | Verdict | Why |
|---|---|---|
| Regulatory / data residency | Holds | A jurisdiction, a sovereignty scheme or a customer contract can require a provider you would not otherwise pick. There is no engineering answer to a legal constraint. |
| Avoiding vendor lock-in | Usually overstated | The insurance premium is paid every sprint; the claim is a rewrite that most organisations never file. |
| Negotiating leverage | Real, rarely priced | A credible second option does move a renewal. Almost nobody compares the discount won against the cost of staying credible. |
| Availability across providers | Mostly a myth | The failure you actually suffer is rarely the provider, and the failover path shares dependencies with the thing that broke. |
| Best-of-breed services | Real, but changes shape | It is a genuine reason, and it converts your architecture problem into a cross-provider data movement problem. |
Two of these deserve more than a table row. The availability claim is the one most often asserted and least often examined, and the lock-in claim is the one that quietly sets the whole architecture. Take them in turn.
The availability argument fails on correlated failure
Run the post-incident reviews from the last two years and count how many root causes a second provider would have prevented. In most estates the honest answer is close to none. The outages were a configuration push, an expired certificate, a schema migration that locked a hot table, a dependency upgrade, a DNS record edited by hand, a quota reached at the worst moment, a retry storm that turned a slow dependency into a dead one. Every one of those follows your code and your change process into whichever cloud you deploy to.
Provider-wide, all-region failures are rare. Regional and zonal impairments are not, and those are addressed by a second region, which is a far cheaper control. Worse, the escape route is usually correlated with the thing it is meant to escape. The failover is triggered by health checks configured in one provider, executed by a pipeline running in one provider, using artefacts from one registry, authorised by one identity plane, and steered by DNS records managed in one console. If your control plane lives on the side that is down, the second cloud is a warm room full of servers you cannot reach.
There is a narrower version of the claim that does hold: a provider-level account failure — a billing suspension, a compromised organisation-level credential, a mistaken policy applied at the root — can take out every region at once in a way no regional design survives. That is a real risk, but it is answered by an out-of-provider copy of data and configuration, not by running live traffic on two clouds.
The portability spectrum, and what each rung actually buys
"Portable" is not one property. It is a ladder, and each rung costs more than the one below while buying less than teams expect.
Container image
The image makes the process reproducible: the same binary, the same dependencies, the same entrypoint. It says nothing about what surrounds the process. The image does not carry the load balancer that fronts it, the secret it reads at start-up, the queue it consumes, the IAM identity it runs as, or the log sink it writes to. Container portability is real and cheap, and it is a small fraction of what moving a workload involves.
Kubernetes
Kubernetes makes the shape of a deployment portable: scheduling, rollout semantics, service discovery, config and secret injection as an API. In practice, the manifests that matter are the ones that are not portable. Ingress objects carry provider-specific annotations. Storage classes name provider volume types with different performance and resize semantics. Service accounts are annotated with provider identity bindings. The cluster autoscaler, the CNI, the CSI drivers, the load balancer controller and the node image are all provider-coupled. You get a portable orchestration API sitting on a non-portable substrate, and the manifests fork the first time somebody needs a managed database.
A full abstraction layer
The top rung is an internal platform that hides providers entirely behind your own resource types. This works, and it is the most expensive software your platform team will ever own. It can only expose the intersection of provider capabilities, so every service is reduced to its least capable version and every new provider feature arrives late or never. It becomes a product with a roadmap, a support queue, a migration story of its own, and a page at three in the morning when its reconciler is the reason a deploy failed.
Why the abstraction usually costs more than the lock-in
Set the two costs side by side, because they are not the same kind of number. The cost of lock-in is a contingent, deferred, one-time cost: if you ever leave, you pay to rewrite the coupled parts. It may never be incurred, and if it is, it is incurred once, with a budget, a plan and a deadline. The cost of avoiding lock-in is certain, continuous and distributed: every team pays it in every sprint, in the form of the managed feature they were not allowed to use, the abstraction they had to learn, the extra indirection they had to debug, and the platform headcount that maintains it.
Put crudely, the abstraction is an insurance premium billed monthly against a claim most organisations never file — and unlike insurance, the premium grows with the size of the estate rather than staying flat.
This is not an argument for coupling to everything. It is an argument for being deliberate about where the coupling sits. The usual good answer is to isolate rather than abstract: keep provider-specific calls behind an interface in your own codebase, so the coupling is confined to a named module you could rewrite, and do not build a general mechanism to make it swappable. An interface with one implementation costs a day. A layer that supports two providers costs forever, and it is a lie about your test coverage until you actually run both in production.
The exception is genuinely commodity primitives — object storage, virtual machines, DNS, block volumes. Their APIs differ but their semantics mostly agree, so a thin shim over them is cheap and honest. The expensive abstractions are always over the opinionated services: the managed database, the event bus, the identity plane, the data warehouse. Those are the ones people most want to abstract, and the ones where the intersection of features is thinnest.
Data gravity and egress are the binding constraint
Everything above is about compute, and compute is the easy half. The reason workloads do not move is that their data already landed somewhere. Provider pricing is directional — getting data in is cheap or free, getting it out is not; the line-item mechanics belong to cloud FinOps and the network paths to cloud networking. What matters here is the structural consequence of that asymmetry: it is a ratchet. Every day of ingest raises the price of the exit, and nobody ever schedules the day on which the ratchet is examined.
The practical result is that the second provider becomes a satellite. It can read, it can serve derived results, it can host stateless front ends — but the authoritative dataset stays where it accumulated, because moving it costs real money on the way out and the copy has to be kept current afterwards. That "afterwards" is the part budgets miss: a cross-provider replica is not a one-time transfer but a permanent stream, and its cost scales with change rate rather than with dataset size.
Analytics makes this sharper because it amplifies reads. A query engine in one provider scanning object storage in another does not read the dataset once; it reads the relevant partitions again for every query, every dashboard refresh and every backfill. A pipeline that would be unremarkable within a region becomes a recurring transfer bill when the compute and the bucket sit on opposite sides.
And the cruel timing: egress on a failover path is charged precisely when you are already having your worst day. A design that promises to shift traffic to another provider during an incident is also promising a transfer bill exactly when nobody is watching the budget. Whether the data can move at all — and what the cutover looks like — is developed in cloud migration patterns.
There is no shared root of trust
Two providers means two identity planes that have never heard of each other. Each will federate with the other, but the trust is configured pairwise and it has a direction: a workload in A assuming a role in B is a different configuration from the reverse, with a different token exchange, different claim mapping and different audit trail. The mechanics of principals, roles, short-lived credentials and trust policies belong to cloud IAM; the cross-provider question is narrower and sharper.
Someone has to be the root. Either you nominate one provider's identity plane as the hub and let the other trust it — in which case you have made that provider a tier-zero dependency for everything, which is precisely the lock-in the exercise was meant to avoid — or you put a neutral external identity provider in the middle, which is architecturally cleaner and means you now operate a tier-zero service yourself, with its own availability target and its own blast radius.
The same fork appears one level down with credentials. Access to provider B usually requires something held in provider A: a client secret, a signing key, a federated trust configuration. Storing it as a long-lived secret recreates the static credential problem that workload federation exists to remove; see cloud secrets management for handling and rotation. The design to aim for is short-lived tokens exchanged in both directions, no standing credential on either side, and one auditable place where the trust relationships are declared — because a trust edge nobody remembers creating is the most dangerous object in a two-provider estate.
Observability, and the single pane that is not one
Each provider gives you a good console for its own resources and nothing for anyone else's. Stitching them together is harder than it looks, because the disagreement is semantic rather than cosmetic. Metric names and dimensions differ. Percentiles are frequently pre-aggregated on the provider side, and pre-aggregated percentiles cannot be averaged or merged across sources without producing a number that is simply wrong. Log records arrive with different schemas, different timestamp precision and different guarantees about ordering and delivery. Trace context propagates by default in one place and needs explicit instrumentation in the other, so a request that crosses the boundary shows up as two unrelated traces.
The workable answer is a provider-neutral collection layer — agents emitting a common wire format into one backend — which is the right architecture and adds two costs. It duplicates telemetry you are already paying the provider to store, and it moves telemetry across the boundary, so your observability pipeline is itself a steady cross-provider transfer.
The cost that hurts most is not technical. During an incident, the responder has to hold two mental models: two consoles, two quota systems, two status pages whose language differs, two support portals with different severity ladders and different response clocks. Correlating an event in one provider with an effect in the other has no shared identifier unless you created one, which means propagating your own request ID end to end and indexing on it. Do that early or you will do it during an outage.
Two of everything is the real invoice
The recurring cost of a second provider is not compute, and it is not even mainly the transfer. It is that every cross-cutting concern needs a second implementation, kept in step forever.
Infrastructure as code. Two providers do not mean one module with a flag. The resource graphs genuinely differ — different dependency orders, different lifecycle rules, different things that force replacement on change — so you maintain two module trees, two state backends, two sets of provider version pins, and you discover the divergence when a change works in one and quietly does something else in the other.
Security baseline. Network egress controls, encryption defaults, logging destinations, key policies and public-access blocks are all expressed in provider-specific vocabulary. Every new control is designed once and implemented twice, and the second implementation is always the one that lags.
Compliance evidence. Auditors want evidence per environment, not per company. Two providers means two control mappings, two sets of attestations to collect, two audit-log pipelines to prove complete, and twice the sampling. This is pure overhead with no engineering upside, and it is the cost most often left out of the business case.
Expertise. The scarcest resource is depth, and a second provider halves it. Two providers with the same headcount produces two shallow benches rather than one deep one, and the shallow bench is exposed exactly when something unusual breaks. Add two support contracts, two escalation paths and two patch cadences, and the operational surface roughly doubles while the team does not.
Active-active, active-passive and partitioned are not the same thing
Three quite different architectures get called multi-cloud in the same meeting, and conflating them is how expectations get set that nobody can meet.
Workload-partitioned
Different applications run on different providers, each wholly in one place. This is by far the most common honest form, and the cheapest: nothing has to be portable, because nothing moves. It is worth being clear that it buys no resilience whatsoever. If the provider hosting a workload fails, that workload is down, exactly as it would be with one provider. What it does buy is best-of-breed placement and, sometimes, a real negotiating position.
Active-passive
A standby copy of the same system sits in the second provider. The hard truth about the passive side is that it is unexercised, and unexercised capacity is a hypothesis. Either you pay for enough standby to absorb full production — expensive, and mostly idle — or you rely on scaling up during the incident, which is the moment when capacity is least likely to be available and least likely to be well tested. Add the replication lag question, which decides how much data you lose, and the failover-decision question, which decides how long you argue before acting.
Active-active
Both sides serve live traffic. The routing part is the easy part and belongs to DNS failover and traffic steering. The hard part is the data layer, and it is not a cloud problem at all: you need multi-master with conflict resolution, or a clean partition of the keyspace so each side owns its own writes. Whichever you choose, you have taken on a distributed-systems problem that exists identically across two regions of one provider — at a fraction of the latency and none of the cross-provider transfer. Recovery objectives and the exercises that validate them are developed in cloud disaster recovery.
The decision, stated honestly
Multi-cloud is genuinely right in a small number of situations, and they are recognisable. A regulator, a sovereignty regime or a signed customer contract names a provider: there is nothing to debate. An acquisition you will operate for years rather than absorb in months: run it properly as a second estate instead of pretending the migration is imminent. One genuinely superior managed service where the data can live next to it rather than commuting. A concentration limit imposed on you, common in regulated finance, where a supervisor requires demonstrated ability to exit a provider — note this usually demands a proven exit path, not live dual-running.
For nearly everything else, a second region on one provider is the better trade. It gives an independent physical failure domain, the same IAM model, the same infrastructure code, the same on-call runbooks, the same tooling and support relationship, no cross-provider transfer, and a failover path your team can actually rehearse — and it addresses the regional and zonal failures that make up almost all real outage minutes.
The test that cuts through the debate has two parts. First: name the specific failure you are buying protection against, and check whether it has ever happened in a form that a second region would not have covered. Second: if the answer is resilience, ask when you last failed over on purpose, in business hours, with real traffic. An untested second cloud is not a resilience control. It is a second estate with a story attached, and it invoices monthly either way.