From cloud-native to platform-native: How Dapr powers multi-Environment engineering
Cloud Native has been _THE_ most used buzzword since containerisation stepped onto the scene more than a decade ago. It revolutionized how application developers not only develop their applications but also how they deploy them. In the more recent future, everyone talks about platforms and platform engineering and how it helps developers to achieve their goals more quickly. However, one thing always stays somewhat complicated. Even the most sophisticated Platform needs to run in some kind of an environment, and typically, throughout a modern SDLC, an application will run in multiple. It's finally time, let’s make it easy.
Dapr: A unified abstraction for local and production environments
Modern distributed applications face a recurring challenge: every service, every component, every team ends up reinventing the wheel when integrating with infrastructure. Need to talk to a database? Write custom connection logic. Need to publish an event? Choose a broker, implement the SDK. Need service discovery? Implement it yourself - or hope your cloud provider has a managed solution. The result? A mess of tightly coupled, environment-dependent, and often redundant code that developers have to maintain across multiple applications and multiple environments.

Dapr (Distributed Application Runtime) solves this by providing a unified API that abstracts these concerns away. Instead of every microservice implementing its own logic for service-to-service communication, state management, pub/sub messaging, or secrets retrieval, Dapr provides a consistent, environment-agnostic API for all of them. This means developers no longer need to worry about the underlying infrastructure, whether they’re working locally, in Kubernetes, or across multiple clouds, Dapr ensures the same application logic just works.
At its core, Dapr acts as an abstraction layer over platform-specific implementations, offering application developers a powerful yet simple way to interact with their environment. Need a message queue? Use the Dapr pub/sub API, whether it’s backed by Kafka, RabbitMQ, or Azure Service Bus, your application code remains unchanged. Need distributed state management? The same API works across Redis, Cosmos DB, PostgreSQL, and more. Dapr doesn’t replace these technologies; it sits on top, making them accessible through a unified interface.
And the best part? Developers love it. No more writing boilerplate code for infrastructure plumbing. No more being locked into a specific cloud provider’s SDKs. No more painful migrations when switching backends. Whether running on a laptop during local development or scaling up in a production Kubernetes cluster, Dapr ensures applications behave the same way everywhere.
This isn’t just a convenience - it’s a game changer.
Dapr architecture
Dapr achieves this by being divided into two distinct parts. The first part is the Dapr runtime, which is the core of Dapr, responsible for orchestration and acting as a portable control plane. The second part is the sidecar, which is unique to each Dapr-enabled application. A sidecar is a secondary process running alongside the application, serving as a transparent companion. When an application needs to use a building block, it communicates through the sidecar, which facilitates the use of the specified component. Integrating with a sidecar is straightforward, as all building blocks are exposed as HTTP or gRPC-based APIs. Applications simply call their own sidecar, which provides access to the necessary APIs to utilize the building blocks.
Building blocks
As of the freshly released version 1.15, Dapr provides multiple building blocks, with different maturities:
- Service Invocation: Service invocation allows applications to interact through well-defined endpoints using HTTP or gRPC messages. Dapr offers an endpoint that functions as a reverse proxy with integrated service discovery, incorporating distributed tracing and error handling.
- State Management: Application state refers to any data an application needs to retain beyond a single session. Dapr offers key/value-based state and query APIs with pluggable state stores for persistence.
- Pub/Sub Messaging: Pub/Sub is a loosely coupled messaging pattern in which publishers send messages to a topic, and subscribers subscribe to that topic to receive the messages. Dapr facilitates the pub/sub pattern for communication between applications.
- Workflows: The Workflow API allows you to define long-running, persistent processes or data flows that involve multiple microservices using Dapr workflows or workflow components. It can be integrated with other Dapr API building blocks, enabling workflows to invoke other services or retrieve secrets, thus offering flexibility and portability.
- Resource Bindings: A binding provides a two-way connection to an external cloud or on-premise service or system. Dapr enables you to invoke the external service through its binding API and allows your application to be triggered by events from the connected service.
- Actors: An actor is a self-contained unit of computation and state with single-threaded execution. Dapr offers an actor implementation based on the virtual actor pattern, providing a single-threaded programming model and automatically garbage collecting actors when they are not in use.
- Secrets: Dapr offers a secrets building block API that integrates with various secret stores, including public cloud stores, local stores, and Kubernetes, to manage secrets. Services can use the secrets API to retrieve sensitive information, such as a database connection string.
- Configuration: The Configuration API allows you to retrieve and subscribe to application configuration items from supported configuration stores. This enables an application to access specific configuration information, such as during startup or when changes are made in the configuration store.
- Distributed Lock: The distributed lock API allows you to lock a resource, ensuring that multiple instances of an application can access the resource without conflicts and maintain consistency guarantees.
- Cryptography: The Cryptography API allows you to perform cryptographic operations, such as encrypting and decrypting messages, without exposing keys to your application.
- Jobs: Manage the scheduling and orchestration of jobs and background tasks. Those can be repeated in a cron-like fashion, or run on demand.
- Conversations: The Conversations API allows applications to interact with Large Language Models (LLMs) using structured prompts and context-aware processing, building on the Actors building block
Introducing Dapr components
One of Dapr’s most powerful features is its interchangeable components, enabling true portability across environments. Dapr abstracts the underlying infrastructure by providing a consistent API, regardless of where an application runs.
To leverage a Dapr building block, such as Pub/Sub Messaging, you define a component. For instance, if using RabbitMQ for local development, the configuration might look like this:
```
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: order-pub-sub
spec:
type: pubsub.rabbitmq
version: v1
metadata:
- name: host
value: "amqp://localhost:5672"
scopes:
- orderprocessing
- checkout
```
However, when deploying to a cloud environment using Azure Service Bus, the only change required is the component configuration - your application code remains untouched:
```
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: order-pub-sub
spec:
type: pubsub.azure.servicebus.topics
version: v1
metadata:
- name: connectionString
value: "Endpoint=sb://{ServiceBusNamespace}.servicebus.windows.net/;SharedAccessKeyName={PolicyName};SharedAccessKey={Key};EntityPath={ServiceBus}"
scopes:
- orderprocessing
- checkout
```
This decoupling of infrastructure and application logic allows developers to write and test applications in one environment and deploy them seamlessly across different cloud providers or on-premise environments - without modifying their code.
Deploy Dapr Alongside Your App with GitOps
As mentioned earlier, Dapr components are interchangeable, meaning the Dapr sidecar dynamically handles message dispatching based on the configured component. This abstraction provides seamless portability across environments, enabling developers to write code without worrying about infrastructure-specific details.
While this flexibility is powerful, managing Dapr configurations manually isn’t scalable, especially in cloud-native environments. Instead, we can leverage GitOps to declaratively define and deploy Dapr components alongside our applications.
Managing Dapr components with GitOps
Since Dapr components are defined as Kubernetes CRDs (kind: Component), they can be:
- Versioned in Git, ensuring reproducibility and auditability.
- Reviewed through pull requests before deployment.
- Applied automatically using GitOps operators like ArgoCD or Flux.
By treating Dapr components as code, platform teams can enforce environment-specific configurations without manual intervention while ensuring consistency across multiple clusters and deployments.
Deploying Dapr components with ArgoCD
With ArgoCD or Flux, any updates to this manifest are automatically applied to the cluster, ensuring a declarative and automated deployment of Dapr components.
```
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp
spec:
destination:
server: https://kubernetes.default.svc
namespace: myapp-namespace
source:
repoURL: https://github.com/my-org/gitops-repo.git
targetRevision: main
path: environments/prod/myapp
syncPolicy:
automated:
prune: true
selfHeal: true
```
With GitOps, consistency across environments is achieved by deploying the same application code with minimal differences in configurations. All Dapr components, such as state stores, pub/sub, and secrets, are stored in Git, ensuring they are declarative and versioned, providing visibility and auditability. In case of failures, seamless rollbacks are possible, allowing you to revert to previous versions of both the application and its Dapr components. Additionally, self-healing deployments ensure that if a Dapr component is deleted or modified manually, GitOps tools will automatically restore it to the desired state.
How's that platform native?
Just as Dapr abstracts away the complexities of distributed systems, allowing applications to seamlessly transition across environments, GitOps creates a consistent and automated way to manage infrastructure and configurations. By treating your application and its Dapr components as part of the same declarative infrastructure, you not only streamline development workflows but also enable the true flexibility and scalability of platform engineering. This shift to a platform-native mindset ensures that your entire platform, from local development to production, is unified, portable, and self-healing, providing developers with a seamless experience across multiple environments. With Dapr and GitOps, you are no longer confined to specific infrastructure setups, but instead, you unlock the full potential of modern, cloud-native platforms.