What I Learned Building Cloud-Portable Services Across Multiple Providers
Multi-cloud strategies often stumble over provider-specific behavior. A layered abstraction built on official SDKs can normalize differences while preserving access to valuable native capabilities.
Teams embarking on multi-cloud journeys often start with a solid business case and clear architecture diagrams. However, reality tends to diverge from the initial plans quickly. Building services across cloud providers like AWS, GCP, and Alibaba Cloud reveals a recurring challenge: fragmentation in development experiences that no amount of upfront planning can fully address.
A consistent pattern emerges where teams, aiming for portability, encounter semantic differences that derail their progress. The scale of this issue is massive, with a 2024 Gartner report indicating that over 92% of large enterprises now operate in multi-cloud environments. The real engineering challenge, however, lies in reconciling the behavioral differences across cloud services, which extends beyond mere architectural discussions.
Semantic differences manifest in various ways. For instance, deletion of non-existent objects yields different responses across providers—while some return a success message, others return a 404 error. This may seem trivial, but each service team writing portable code must handle these discrepancies independently. Pagination also exhibits semantic inconsistencies.
Some platforms provide explicit continuation tokens, while others generate cursors from the last document returned. These are not mere bugs but fundamental design decisions embedded within each platform. Without abstraction, teams redundantly implement provider-specific code paths, leading to duplicated effort and accumulating technical debt over time.
Previous efforts at multi-cloud abstraction, such as Apache jclouds, relied on REST-based approaches. The idea was simple: REST serves as the shared layer. However, cloud providers continuously evolve their APIs, introducing new features, altering authentication flows, and optimizing performance. REST-based abstractions inevitably fall behind, creating widening gaps with each provider update.
Leveraging official provider SDKs provides a more effective solution. Cloud vendors heavily invest in their SDKs, handling tasks such as request signing, header management, retry logic, timeout handling, and endpoint discovery. By leveraging these SDKs, abstraction layers can focus on normalization rather than infrastructure plumbing.
When providers update their SDKs, those enhancements flow through seamlessly without the need for manual catch-up. A layered architecture for provider abstraction has proven effective. It involves three main layers: a portable client layer providing developers with stable, cloud-neutral APIs; a driver layer responsible for validation and coordination; and provider-specific implementations that normalize behavior by handling status codes, unifying pagination patterns, and standardizing error handling.
With this setup, application teams interact solely with the top layer, while all provider complexities remain hidden beneath. This approach aligns with the broader trend of managing infrastructure complexity better. Adoption of internal developer platforms surged from 23% in late 2024 to 27% in 2025, showcasing a growing recognition that developers need insulation from platform-level details.
Multi-cloud SDKs play a parallel role at the provider level, creating consistent interfaces to allow engineers to focus on business logic rather than cloud-specific integration work. The decision between portability and provider-specific capabilities hinges on cost leverage versus business-critical functionality. Approximately 90% of cloud services are commodities (e.g., compute, object storage, pub/sub messaging) that are sufficiently standardized across providers, making abstraction sensible in these areas.
However, the remaining 10% of services represent genuine differentiators where native integration becomes essential if it offers significant cost advantages or competitive edges. The goal isn't to pursue portability for its own sake but to make deliberate choices about where portability truly matters and where specialized capabilities justify the tradeoff.
Testing across providers necessitates rigorous conformance testing. The most effective method involves writing tests against abstract driver classes and running the same suite against each provider's implementation. Any behavioral deviations are immediately identified. The challenge lies in executing these tests in CI environments where managing live credentials for multiple cloud providers poses security risks.
One solution entails using tools like WireMock as a forward proxy, recording real HTTP transactions on developer machines using credentials, then replaying them in CI. This enables reliable integration testing without exposing production secrets while still validating actual request and response flows. Despite the strategic focus on vendor lock-in driving multi-cloud adoption—cited by 86% of enterprises as a primary motivation—most multi-cloud strategies revolve around infrastructure-level concerns like regions, availability zones, and failover policies.
Surprisingly, developer experience rarely gains attention in these discussions until teams have already invested heavily in implementation. Provider-level abstraction layers help bridge this gap, but they demand deliberate investment. The notion of switching clouds by merely changing configuration rather than rewriting code appears simple in design reviews.
Achieving this requires addressing semantic differences operation by operation, building conforming layers that ensure consistent behavior across providers.
Written by urgent.news from DevOps.com's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.