[KongchangAI]
· 3 min read· 1,748 words

Adaptive Applications: An Architectural Pattern for Making Apps Portable Across Cloud and On-Premises

Adaptive Applications: An Architectural Pattern for Making Apps Portable Across Cloud and On-Premises

Adaptive Applications uses capability abstraction and recipes to let the same code move freely across cloud, on-premises, and edge.

Adaptive Applications is an architectural pattern addressing data sovereignty, compliance, and business continuity needs. Its core is separating "what capabilities an application needs" from "how different environments provide them." Applications program against capability endpoints rather than platform SDKs; databases, caching, identity, and AI inference are managed through the same abstractions. Developers program against capability abstractions, while platform teams write recipes for different environments — resource definitions establish the contract, recipes determine the implementation. For legacy systems, an AI agent fleet analyzes code, identifies coupling, and generates artifacts with critical review agents. The pattern is toolchain-agnostic, and deployment is deliberately unremarkable — a single rad deploy does the job.

Why Cloud-Native Applications Need to Revisit "Portability"

Over the past few years, cloud-native architecture has achieved tremendous success in elasticity, observability, and delivery efficiency. But in an episode of the Azure Essentials Show, guest Haishi pointed out that more and more customers are raising new constraints: data sovereignty, compliance requirements, intermittent network connectivity, and even special hardware integration. At the core, all of these needs point to the same issue — business continuity.

Enterprises want to run well on Azure while also being able to migrate critical systems to on-premises infrastructure managed by Azure Arc, or to edge environments, when necessary. This is exactly the tension that the Adaptive Applications architectural pattern attempts to resolve: completely separating "what the application needs" from "how different environments provide it."

Illustration of application capability abstraction

Azure Arc is Microsoft's hybrid and multi-cloud management platform. It extends Azure's management capabilities (such as policies, RBAC, monitoring, and GitOps configuration) to any infrastructure outside of Azure — including on-premises data centers, other public clouds, and edge devices. Resources brought under Arc management appear as first-class citizens in the Azure portal, so enterprises can manage cloud and on-premises workloads with the same toolchain.

In data sovereignty and compliance scenarios, Arc's value is especially prominent: when regulations require data to remain on-premises or in a specific geographic region, business logic can run on Arc-managed on-premises Kubernetes clusters while still under Azure's unified governance. This is precisely the infrastructure prerequisite that allows the Adaptive Applications pattern to be implemented across environments — without a unified control plane like Arc, the capabilities above the abstraction layer would be difficult to provide and observe consistently across different environments.

The Core Idea: Program Against "Capabilities," Not "Platforms"

The traditional approach is for applications to directly depend on a specific platform's SDK or service endpoints, requiring code changes whenever the environment changes. Adaptive Applications advocates for capability-oriented thinking.

Take AI applications as an example: what the application truly needs is simply the capability of "AI inference" and an accessible endpoint. Whether that endpoint is backed by Azure OpenAI or a locally deployed open-source model doesn't matter to the application code. As long as the abstraction layer remains unchanged, deploying to Azure connects to a cloud model, and deploying to a self-contained on-premises environment switches to a local model managed by Kaito — the application itself requires no modification.

The key to this pattern is: platform-level dependencies are hidden behind capability abstractions, and how capabilities are constructed becomes a separate concern.

Beyond AI: The Same Logic for Databases, Caching, and Identity

Haishi specifically highlighted a common misconception: many developers believe that simply adopting cloud-native patterns and continuously iterating on applications makes code naturally portable. But in reality, applications often depend on platform-level capabilities such as authentication identity and analytics services, and these capabilities may not migrate along with the application.

In the demo, the team showcased not only the abstraction of AI dependencies but also how databases, caching, and identity systems can be managed through the same set of abstractions.

Illustration of object model and design alignment

Redis plays a key role here. Haishi, who was involved in the Redis project early on, pointed out that Redis's object model aligns well with this design: capabilities can be abstracted as resources, and different recipes can be defined for different environments. For example, define a SQL database resource — on Azure, instantiate Azure SQL using ARM templates or Terraform templates; on-premises, use another set of templates to instantiate a local SQL Server instance. Resource definitions establish the contract; recipes determine the implementation.

How Responsibilities Are Redistributed Between Developers and Platform Teams

This pattern clearly distinguishes two types of roles. Developers program against capabilities, with their daily work being to call abstracted endpoints and resources, without needing to care about differences in the underlying environment; platform teams are responsible for writing and maintaining recipes for different environments, ensuring capabilities are correctly provided in target environments.

To make the pattern smoother to adopt, the team defined a series of Redis resource extensions covering common abstraction scenarios, along with command-line tools for generating Redis artifacts and deploying applications in a streaming manner. There is also documentation, tutorials, and general guidance for tricky issues like data synchronization — because data synchronization approaches vary greatly across platforms, making it difficult to have a one-size-fits-all template.

Haishi emphasized that this is essentially a design pattern and is not tied to any specific toolchain. Teams can adopt and adapt it at their own pace.

Recipes are the core implementation mechanism in Adaptive Applications. They are a set of parameterizable infrastructure-as-code templates (such as ARM, Bicep, or Terraform) responsible for instantiating abstract resource definitions into real services in concrete environments.

The key to recipes is the "separation of contract and implementation": resource definitions only declare what the application needs (for example, a SQL-compatible database, a Redis-compatible cache), while the recipe determines which cloud, which product, and what specifications will satisfy it. The same resource definition can be bound to multiple recipes, corresponding to Azure production environments, self-contained on-premises environments, or edge environments. Platform teams maintain recipe versions and adaptations, while developers remain completely unaware of the differences. This mechanism also allows enterprises to package their internal proprietary platforms as recipes and publish them externally, gaining more users in the ecosystem.

Transforming "Brownfield" Applications with an AI Agent Fleet

For large legacy systems that already exist, how to introduce this pattern is the most frequently asked question. The team's approach is to leverage large models' ability to understand codebases:

  • Analyze existing codebases to identify dependencies tightly coupled to the platform;
  • Produce a gap list of required changes;
  • Further generate necessary artifacts so developers can quickly deploy, run trials, observe gaps, and continuously iterate.

Using AI to analyze codebases

The command-line tool shown in the demo uses a fleet of agents design: there are agents responsible for generation and critique agents responsible for critical review, ultimately producing a detailed summary of "what was changed and what was deleted."

Integration with skills provided by the Radius team

The tool has already been integrated with skills provided by the Radius team, with plans to integrate more skills, and welcomes community contributions. However, Haishi also admitted that this tool is still in its early stages.

Brownfield applications is a common term in software engineering, referring to systems that already exist and have been running for a long time, carrying business operations but with aging technology stacks — as opposed to "greenfield applications" built from scratch. The difficulty of brownfield transformation lies in: large codebase scale, deep platform coupling, lack of complete documentation, and the inability to take downtime for a rewrite.

Traditional brownfield modernization often relies on manually reviewing code and identifying dependencies one by one, which is costly and time-consuming. With large models' semantic understanding of codebases, a list of dependencies tightly coupled to the platform (such as hardcoded service endpoints, proprietary SDK calls) can first be automatically compiled, and then corresponding abstraction layers and artifacts can be generated, allowing developers to validate and iterate incrementally without having to rewrite everything at once. This is also the primary motivation behind the design of the AI agent fleet tool.

A Runnable Multi-Tier Example

The example in the demo is a simple stock trading simulator, including a web frontend, a backend written in another language, a message pipeline, and a conversational agent. For identity, the demo environment uses Keycloak as the identity provider, which can also be changed to Entra or federated with on-premises Active Directory.

The most notable point is how "unremarkable" the deployment is: a single rad deploy command finishes the job, and the rest is handled by the abstraction layer. When switched to Azure, the agent is backed by an OpenAI model; for on-premises deployment, a local model can be chosen.

Radius is the open-source project behind this pattern, and the source of the rad deploy command in the demo. It provides an application definition model that uniformly describes applications, their dependent resources, and environment binding relationships, with the Radius control plane responsible for resolving abstract resources into implementations in concrete environments.

The reason rad deploy appears so "unremarkable" is precisely because all environmental differences are absorbed by recipes and resource abstractions: the same command executed locally and on Azure triggers different underlying templates. Radius itself is not tied to any specific cloud or orchestrator and can run on top of Kubernetes, which also confirms what Haishi said: "This is a design pattern, not a product" — Radius is merely one reference implementation of the pattern, and teams can absolutely build equivalent capabilities based on their existing toolchains.

How to Get Started

If this pattern hits a pain point for you, the official next steps are straightforward: first read the pattern documentation in the Azure Architecture Center, then get all the code, examples, and documentation from the public repository. The author found the simple experimental experience very smooth — you only need one machine to run everything.

For teams with proprietary cloud platforms or on-premises systems, you can also write and publish your own recipes, and the official team has expressed willingness to showcase them, bringing users to your platform.

Key Takeaway: Adaptive Applications is not a product, but an architectural approach that abstracts platform dependencies into capabilities. It allows applications to maintain the same codebase across cloud, on-premises, and edge — a capability that is becoming increasingly important under today's compliance, sovereignty, and continuity demands.

One-line Summary

Adaptive Applications uses capability abstraction and recipes to let the same code move freely across cloud, on-premises, and edge.

Paragraph Summary

Adaptive Applications is an architectural pattern addressing data sovereignty, compliance, and business continuity needs. Its core is completely separating "what capabilities an application needs" from "how different environments provide those capabilities." Applications program against capability endpoints rather than binding to a specific platform SDK; platform-level dependencies such as databases, caching, identity, and AI inference are all managed through the same set of abstractions. Developers program against capability abstractions, while platform teams write recipes for different environments — resource definitions establish the contract, recipes determine the implementation. For legacy systems, the team uses an AI agent fleet to analyze codebases, identify coupling, and generate artifacts, complete with critical review agents. The pattern is not tied to any specific toolchain, and the deployment experience is deliberately made unremarkable — a single rad deploy completes the job.

#Adaptive Applications#cloud portability#Azure Arc#capability abstraction#recipes infrastructure as code#AI agent fleet#brownfield modernization#Radius
Share:

Related articles