DAPR
Dapr (Distributed Application Runtime) is a portable, event-driven runtime that makes it easy to build resilient microservices across cloud and edge, in any language. It is a graduated CNCF project.
Dapr is a portable, event-driven runtime that makes it easy for any developer to build resilient, stateless, and stateful applications that run on the cloud and edge and embraces the diversity of languages and developer frameworks.
In practice, Dapr packages the hard parts of distributed systems — service-to-service calls with retries and mTLS, state storage, publish/subscribe messaging, secrets, and more — behind a simple, consistent API your app calls over localhost. You write business logic; Dapr handles the plumbing.
Why Dapr?
Every microservice team ends up rewriting the same infrastructure code:
- Service discovery, retries, timeouts and mTLS for service-to-service calls
- Reading and writing state to a database or cache
- Publish/subscribe messaging between services
- Loading secrets and configuration
- Talking to external systems (queues, blob stores, SaaS APIs)
Dapr provides each of these as a reusable building block with pluggable implementations, so you can swap Redis for PostgreSQL, or RabbitMQ for Kafka, by changing a YAML file — not your code.
Architecture: the sidecar model
Dapr runs as a sidecar — a separate process (or container) that lives next to your application. Your code talks to the sidecar over HTTP or gRPC on localhost; the sidecar does the distributed work and communicates with other sidecars and infrastructure.
Because the API is just HTTP/gRPC on localhost, Dapr is language-agnostic: any app that can make an HTTP call can use it. Official SDKs (Python, .NET, Java, Go, JavaScript and more) wrap the same API for convenience. By default the sidecar serves HTTP on port 3500 and gRPC on 50001.
Building blocks
Each capability Dapr exposes is a building block, reachable at a versioned API path (/v1.0/...):
- Service Invocation — direct, secure service-to-service calls with discovery, retries and mTLS.
- State Management — key/value storage with consistency and concurrency options.
- Publish & Subscribe — decoupled messaging over a broker.
- Bindings — trigger your app from, or send data to, external systems.
- Actors — the virtual-actor pattern for stateful, single-threaded objects.
- Secrets — read secrets from a vault without hard-coding them.
- Configuration — read and subscribe to application configuration.
- Workflow — author long-running, durable workflows as code.
- Distributed Lock & Cryptography — mutual exclusion and encrypt/decrypt APIs.
Components
A building block is backed by a component — a YAML file that selects a concrete implementation and its settings. This is how Dapr stays pluggable. Here is a Redis-backed state store named statestore:
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: statestore
spec:
type: state.redis
version: v1
metadata:
- name: redisHost
value: localhost:6379
- name: redisPassword
value: ""
Swap spec.type to state.postgresql, state.mongodb and so on, and your application code does not change.
Getting started
Install the CLI, initialise Dapr locally, and run your app with a sidecar:
# Install the CLI (macOS/Linux)
curl -fsSL https://raw.githubusercontent.com/dapr/cli/master/install/install.sh | bash
# Initialise Dapr locally (sets up Redis, Zipkin and the placement service in Docker)
dapr init
# Run your app WITH a Dapr sidecar
dapr run --app-id orders --app-port 8080 --dapr-http-port 3500 -- python app.py
dapr init provisions Redis (default state and pub/sub), Zipkin (tracing) and the placement service in Docker, so the examples below work out of the box.
Example: Service Invocation
To call another service, address its app-id through your own sidecar — Dapr handles discovery, retries and mTLS:
# Call the "process" method on the "checkout" service via your local sidecar
curl http://localhost:3500/v1.0/invoke/checkout/method/process \
-H "Content-Type: application/json" \
-d '{ "orderId": "order-1" }'
Your sidecar forwards the request to the checkout app’s sidecar, which invokes its /process route. No hostnames and no client-side load balancing in your code.
Example: State Management
With the statestore component above, save and read key/value state through the sidecar:
# Save state (an array of key/value pairs)
curl -X POST http://localhost:3500/v1.0/state/statestore \
-H "Content-Type: application/json" \
-d '[{ "key": "order-1", "value": { "item": "pizza", "qty": 2 } }]'
# Read it back
curl http://localhost:3500/v1.0/state/statestore/order-1
Or use an SDK — here in Python:
from dapr.clients import DaprClient
with DaprClient() as d:
# Save and read state
d.save_state(store_name="statestore", key="order-1", value="2 pizzas")
state = d.get_state(store_name="statestore", key="order-1")
print(state.data)
# Call another service over Dapr
d.invoke_method(app_id="checkout", method_name="process", data=b"order-1")
# Publish an event
d.publish_event(pubsub_name="pubsub", topic_name="orders", data="order-1")
Example: Publish & Subscribe
Define a pub/sub component (Redis Streams here):
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: pubsub
spec:
type: pubsub.redis
version: v1
metadata:
- name: redisHost
value: localhost:6379
- name: redisPassword
value: ""
Publish an event to the orders topic:
curl -X POST http://localhost:3500/v1.0/publish/pubsub/orders \
-H "Content-Type: application/json" \
-d '{ "orderId": "order-1" }'
Subscribe declaratively — Dapr will deliver matching messages to your app’s /orders route:
apiVersion: dapr.io/v1alpha1
kind: Subscription
metadata:
name: order-sub
spec:
pubsubname: pubsub
topic: orders
route: /orders
Secrets Management
Keep credentials out of code and config. Define a secret store (a local file here; use Vault, AWS/GCP/Azure secret managers, or Kubernetes secrets in production):
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: secretstore
spec:
type: secretstores.local.file
version: v1
metadata:
- name: secretsFile
value: secrets.json
Then read a secret through the sidecar:
curl http://localhost:3500/v1.0/secrets/secretstore/db-password
Components can also reference secrets with secretKeyRef, so connection strings never appear in plain text.
Running on Kubernetes
Install Dapr’s control plane, then opt a workload in with three annotations — Dapr injects the sidecar container automatically:
# Install the Dapr control plane into your cluster
dapr init -k
# Check the status
dapr status -k
apiVersion: apps/v1
kind: Deployment
metadata:
name: orders
spec:
replicas: 1
selector:
matchLabels:
app: orders
template:
metadata:
labels:
app: orders
annotations:
dapr.io/enabled: "true"
dapr.io/app-id: "orders"
dapr.io/app-port: "8080"
spec:
containers:
- name: orders
image: myregistry/orders:latest
ports:
- containerPort: 8080
Observability
Because all traffic flows through sidecars, Dapr emits distributed traces (W3C Trace Context, exportable to Zipkin, Jaeger or any OpenTelemetry backend), Prometheus metrics and structured logs — giving you end-to-end visibility across services without extra code.
When to use Dapr
- You are building several microservices and want to avoid re-implementing messaging, state and resilience in each one.
- You want to stay portable across brokers and stores, and across local, cloud and Kubernetes environments.
- You work in a polyglot team and want one consistent API across languages.
For a single small service with no external dependencies, a sidecar may be more than you need. Dapr’s value grows with the size and complexity of the system.
Comments (0)
Be the first to comment.