Dapr Reference: Service Invocation, Pub/Sub, State Management & Distributed App Runtime
Dapr (Distributed Application Runtime) is a CNCF-graduated project that provides distributed systems building blocks as APIs — service invocation, pub/sub, state management, secrets, bindings, and actors — so your code doesn’t need to implement them. Works on K8s, self-hosted, or locally.
1. Core Building Blocks
What Dapr provides and when to use it
| Building Block | What it does | Example use |
|---|---|---|
| Service Invocation | Synchronous service-to-service calls with retries, mTLS, tracing | frontend calls user-service via Dapr sidecar (no service discovery code needed) |
| Pub/Sub | Async message publish/subscribe with pluggable brokers | order-service publishes OrderCreated; inventory-service consumes it |
| State Management | Key-value store API (Redis, Cosmos, PostgreSQL, etc.) | session data, cart contents, last-known-value storage |
| Secrets | Secret store API (Vault, AWS SM, K8s secrets) | app reads DB password via Dapr — not direct Vault SDK |
| Bindings | Trigger code from or send to external systems (SQS, Kafka, cron, HTTP) | process S3 upload events, send email on order, scheduled job |
| Actors | Virtual actor model for stateful, turn-based processing | IoT device state, saga orchestration, reminder-based workflows |
# Install Dapr CLI: brew install dapr/tap/dapr # macOS dapr init # local mode (runs Redis + Zipkin via Docker) dapr init -k # Kubernetes mode (installs Dapr control plane) # Verify K8s install: kubectl get pods -n dapr-system # dapr-operator, dapr-sidecar-injector, dapr-scheduler, etc. dapr status -k # all component health
2. Service Invocation
Call other services via Dapr — no service discovery, auto mTLS, retries
# Enable Dapr sidecar for a Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-frontend
spec:
template:
metadata:
annotations:
dapr.io/enabled: "true" # inject Dapr sidecar
dapr.io/app-id: "frontend" # this app's Dapr name
dapr.io/app-port: "8080" # port your app listens on
dapr.io/config: "tracing" # optional: tracing config
spec:
template:
metadata:
annotations:
dapr.io/enabled: "true"
dapr.io/app-id: "user-service" # the service being called
# Call another service via Dapr sidecar (from frontend code):
# HTTP: POST http://localhost:3500/v1.0/invoke/{app-id}/method/{method}
curl http://localhost:3500/v1.0/invoke/user-service/method/users/123
# Python example:
import requests
resp = requests.get("http://localhost:3500/v1.0/invoke/user-service/method/users/123")
# Dapr handles: service discovery, mTLS, retries, distributed tracing
# No SDK needed — plain HTTP to localhost:3500 (Dapr sidecar port)
# Dapr routes the call to the right pod regardless of where it's running
# Configure retries + timeout:
apiVersion: dapr.io/v1alpha1
kind: Resiliency
metadata:
name: user-service-resiliency
spec:
targets:
apps:
user-service:
timeout: 10s
retry:
policy: constant
duration: 1s
maxRetries: 3
circuitBreaker:
maxRequests: 1
interval: 10s
timeout: 30s
trip: consecutiveFailures > 3
3. Pub/Sub
Async messaging with pluggable brokers — swap Redis for Kafka with zero code change
# Pub/Sub component (Redis Streams — default for local dev):
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: pubsub
namespace: default
spec:
type: pubsub.redis
version: v1
metadata:
- name: redisHost
value: redis:6379
- name: redisPassword
secretKeyRef:
name: redis-secret
key: redis-password
# Swap to Kafka with zero app code changes:
spec:
type: pubsub.kafka
version: v1
metadata:
- name: brokers
value: kafka:9092
- name: consumerGroup
value: my-group
# Publish a message (HTTP POST to Dapr sidecar):
curl -X POST http://localhost:3500/v1.0/publish/pubsub/orders -H "Content-Type: application/json" -d '{"orderId": "123", "customerId": "456"}'
# Subscribe (app endpoint Dapr calls when message arrives):
# 1. Register subscription in dapr/subscriptions.yaml:
apiVersion: dapr.io/v1alpha1
kind: Subscription
metadata:
name: orders-subscription
spec:
pubsubname: pubsub
topic: orders
route: /orders # Dapr POSTs to this endpoint on your app
# 2. Your app handles it (Python Flask example):
@app.route("/orders", methods=["POST"])
def handle_order():
data = request.json
print(f"Processing order {data['orderId']}")
return json.dumps({"status": "SUCCESS"}), 200
4. State Management
Key-value state store with pluggable backends
# State store component:
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: statestore
spec:
type: state.redis # swap to state.postgresql, state.azure.cosmosdb, etc.
version: v1
metadata:
- name: redisHost
value: redis:6379
# Get, set, delete state (via Dapr HTTP API):
# Set state:
curl -X POST http://localhost:3500/v1.0/state/statestore -H "Content-Type: application/json" -d '[{"key": "user-123-cart", "value": {"items": ["product-1", "product-2"]}}]'
# Get state:
curl http://localhost:3500/v1.0/state/statestore/user-123-cart
# Delete state:
curl -X DELETE http://localhost:3500/v1.0/state/statestore/user-123-cart
# Transactions (multi-key atomic operation):
curl -X POST http://localhost:3500/v1.0/state/statestore/transaction -H "Content-Type: application/json" -d '{
"operations": [
{"operation": "upsert", "request": {"key": "order-1", "value": {"status": "paid"}}},
{"operation": "upsert", "request": {"key": "inventory-1", "value": {"stock": 99}}}
]
}'
# ETags for optimistic concurrency (prevent lost updates):
# GET returns ETag in header
# Include ETag in PUT to fail if state was changed by another process
5. Secrets & Local Development
Secret store API and running Dapr locally with dapr run
# Secret store component (K8s secrets as source):
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: kubernetes
spec:
type: secretstores.kubernetes
version: v1
# Read a secret via Dapr API (your app never talks to K8s API directly):
curl http://localhost:3500/v1.0/secrets/kubernetes/my-app-secrets
# Returns: {"db-password": "...", "api-key": "..."}
# Restrict which secrets an app can read (RBAC in Dapr):
apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
name: app-config
spec:
secrets:
scopes:
- storeName: kubernetes
defaultAccess: deny # deny by default
allowedSecrets: [db-password] # only this secret is accessible
# Run app locally with Dapr sidecar (no K8s needed):
dapr run --app-id my-service --app-port 8080 --dapr-http-port 3500 -- python app.py
# Run with custom components directory:
dapr run --app-id my-service --components-path ./dapr/components \ # local component YAML files
-- python app.py
# List running Dapr apps:
dapr list # local
dapr list -k # Kubernetes
# Dashboard:
dapr dashboard -k # opens web UI with app topology + component status
Track Dapr, Kubernetes, and microservice runtime releases.
ReleaseRun monitors Kubernetes, Docker, and 13+ DevOps technologies.
Related: NATS Reference | Apache Kafka Reference | External Secrets Operator Reference
🔍 Free tool: K8s YAML Security Linter — check your Dapr-enabled K8s workload manifests for 12 security misconfigurations.
Founded
2023 in London, UK
Contact
hello@releaserun.com