Dapr — Structure#
Layout pattern#
Standard Go Layout (cmd/ + pkg/) with Monorepo-like service decomposition
Dapr follows the standard Go project layout: all binaries in cmd/, all library code in pkg/, proto definitions in a dedicated dapr/ directory. However, it extends this by co-locating six independent services in a single repository — each with its own cmd/<service>/ entry point and a corresponding pkg/<service>/ package. This is a controlled monorepo pattern where multiple deployable binaries (daprd, injector, operator, placement, sentry, scheduler) share common infrastructure code under pkg/ without separate module files.
Directory map#
repositories/dapr/
├── cmd/ # Binary entry points (6 services)
│ ├── daprd/ # Main sidecar runtime (+ app/, options/, components/)
│ ├── injector/ # Kubernetes sidecar injector webhook
│ ├── operator/ # Kubernetes operator / CRD controller
│ ├── placement/ # Actor placement service
│ ├── scheduler/ # Job/workflow scheduler service
│ └── sentry/ # Certificate authority (mTLS)
├── dapr/
│ └── proto/ # Protobuf source definitions (runtime, components,
│ # placement, scheduler, sentry, operator, internals)
├── pkg/ # All shared and per-service library code
│ ├── acl/ # Access control list evaluation
│ ├── actors/ # Virtual actor runtime (reminders, timers, state, routing)
│ ├── api/ # HTTP + gRPC API handlers (universal/, http/, grpc/)
│ ├── apis/ # Kubernetes CRD API types (components, resiliency, etc.)
│ ├── apphealth/ # Application health check probing
│ ├── buildinfo/ # Version / git-commit metadata
│ ├── channel/ # App channel abstractions (HTTP + gRPC transport)
│ ├── client/ # Generated Kubernetes clientset / informers / listers
│ ├── components/ # Component loader registry (per building block type)
│ ├── config/ # Configuration loading (env, modes, protocol)
│ ├── cors/ # CORS middleware
│ ├── diagnostics/ # OpenTelemetry tracing + metrics instrumentation
│ ├── encryption/ # State encryption helpers
│ ├── expr/ # Expression evaluation (e.g., routing rules)
│ ├── healthz/ # Internal health endpoint framework
│ ├── injector/ # Webhook handler logic for sidecar injection
│ ├── internal/ # Internal utilities (not for external import)
│ ├── messages/ # Structured error/status messages
│ ├── messaging/ # Service-to-service invocation (direct messaging)
│ ├── metrics/ # Prometheus metrics setup
│ ├── middleware/ # HTTP middleware chain management
│ ├── modes/ # Deployment mode constants (k8s, standalone)
│ ├── operator/ # Operator controller + CRD reconciliation logic
│ ├── outbox/ # Transactional outbox (pub/sub + state atomicity)
│ ├── placement/ # Placement server logic + consistent hashing
│ ├── ports/ # Port allocation utilities
│ ├── proto/ # Generated protobuf Go code (runtime, components, etc.)
│ ├── resiliency/ # Circuit breaker, retry, timeout policies
│ ├── responsewriter/ # HTTP response writer helpers
│ ├── retry/ # Retry policy primitives
│ ├── runtime/ # Core daprd runtime wiring (processor, hotreload, pubsub…)
│ ├── scheduler/ # Scheduler server logic + client
│ ├── scopes/ # Namespace/scope filtering
│ ├── security/ # mTLS, SPIFFE identity, token management
│ ├── sentry/ # Certificate authority server logic
│ ├── sse/ # Server-sent events support
│ ├── testing/ # Shared test helpers (grpc, logging, trace)
│ └── validation/ # Input validation utilities
├── charts/
│ └── dapr/ # Helm chart for Kubernetes deployment
├── docker/ # Dockerfiles (distroless runtime, debug, dev, Windows)
├── docs/ # Decision records, development guides, release notes
├── grafana/ # Grafana dashboard JSON definitions
├── swagger/ # OpenAPI / Swagger spec files
├── tests/ # Integration, e2e, perf tests + test runner
│ ├── apps/ # Test application binaries
│ ├── e2e/ # End-to-end test scenarios
│ ├── integration/ # Integration test suites
│ ├── perf/ # Performance/load tests
│ └── runner/ # Test infrastructure runner
├── tools/
│ └── proto/ # Protobuf code generation tooling
├── utils/ # Miscellaneous top-level utilities
└── .build-tools/ # Internal build-time tooling (cmd/)Entry points#
| Binary | Path | Purpose |
|---|---|---|
daprd | cmd/daprd/main.go | Main sidecar runtime. Registers all components, exposes HTTP+gRPC API to apps, handles all building blocks (pub/sub, state, actors, secrets, bindings, workflows). |
injector | cmd/injector/main.go | Kubernetes mutating webhook that injects the daprd sidecar container into application pods at admission time. |
operator | cmd/operator/main.go | Kubernetes operator that reconciles Dapr CRDs (Components, Configurations, Resiliency policies, Subscriptions, HTTPEndpoints) and streams configuration to sidecars. |
placement | cmd/placement/main.go | Actor placement service that uses consistent hashing (virtual node tables) to route actor invocations to the correct daprd instance. |
scheduler | cmd/scheduler/main.go | Job scheduler service for workflow/timer scheduling, using etcd-backed cron. Added in a later release to offload scheduling from placement. |
sentry | cmd/sentry/main.go | Certificate authority that issues SPIFFE-compatible mTLS certificates to dapr sidecars, enabling mutual TLS for service-to-service calls. |
All main.go files are thin shims that delegate to cmd/<service>/app/app.go. The app.go files handle option parsing, component registration (for daprd), and service startup.
Package organization#
Internal packages (
pkg/internal/): Small set of unexported utilities not intended for external consumption (package nameinternalenforces Go import restriction).Public packages (
pkg/): Everything underpkg/uses descriptive package names aligned with their service or concern. While technically importable, these are not designed as a stable public library — Dapr follows sidecar-model conventions where consumers use the HTTP/gRPC API rather than importing Go packages. Notable public-ish packages:pkg/actors— Virtual actor runtime with sub-packages for API, reminders, timers, state, routingpkg/api— Unified API handler layer withuniversal/,http/, andgrpc/implementationspkg/components— Per-building-block component registries (state, pubsub, bindings, secretstores, etc.)pkg/resiliency— Circuit breaker + retry + timeout policy engine (withbreaker/sub-package)pkg/runtime— Core daprd wiring: processor, component store, hot-reload, pub/sub subscription manager, workflow enginepkg/security— mTLS and SPIFFE identity managementpkg/diagnostics— OpenTelemetry integration with consts and utils sub-packagespkg/proto— Generated protobuf Go stubs for all internal RPC surfaces
Layering: The project uses a hub-and-spoke model rather than strict layered architecture:
pkg/runtimeis the central hub that wires together all building blockspkg/components/<type>packages define loader registries (what’s available)cmd/daprd/components/registers the actual component implementations at startup via blank imports (_ "...")pkg/api/{http,grpc}packages call intopkg/runtimeand specialized packages- Per-service packages (
pkg/placement,pkg/sentry,pkg/scheduler,pkg/injector,pkg/operator) are self-contained and only depended upon by their respectivecmd/binary
Build system#
- Build tool: GNU Make (
Makefile) — comprehensive, with docker.mk included for container targets - Key targets:
make build— Compiles all 6 binaries (daprd, placement, operator, injector, sentry, scheduler) intodist/<os>_<arch>/release/make build-linux— Cross-compiles for Linux (used in Docker image builds)make release— Build + archive (zip on Windows, tar.gz on Linux/Mac)make test— Unit testsmake test-integration— Integration test suitemake lint— golangci-lintmake manifest-gen— Generates Helm YAML manifestmake modtidy-all— Tidy all go.mod files- Proto generation via
make proto(usestools/proto/)
- Build tags:
DAPR_SIDECAR_FLAVORcontrols which components are compiled into daprd (allcomponentsvsstablecomponents), enabling slimmer distributions - Docker: Yes, multi-stage implied (build artifacts copied into distroless
gcr.io/distroless/static:nonrootimages). Variants: standard, debug, dev, Mariner (CBL), Windows. The runtime images are minimal distroless containers.
Notable structural decisions#
Single-repo for all control plane services: daprd, placement, sentry, operator, injector, and scheduler live in one repository. This enables atomic changes across service boundaries (e.g., adding a new proto message touches the definition, generated code, and all service implementations in a single PR). The tradeoff is a larger, more complex repo and per-service build complexity.
Proto-first internal RPC: All inter-service communication (daprd↔placement, daprd↔sentry, daprd↔scheduler, daprd↔operator) is defined in proto files under
dapr/proto/with generated code inpkg/proto/. The source-of-truth proto definitions live in the repo alongside the implementations — no separate proto repo.Component registry via blank imports: The
cmd/daprd/components/directory exists solely to register component implementations via_imports. This pattern cleanly separates “what components exist” (registration at startup) from “how to use them” (interface abstractions inpkg/components/<type>). TheDAPR_SIDECAR_FLAVORbuild tag controls which registration file is compiled in.pkg/api/universal/unification layer: HTTP and gRPC APIs share business logic via auniversalpackage rather than duplicating handler code. This is an uncommon pattern that avoids drift between the two API surfaces.Extensive
fake/andmock/sub-packages: Key packages (pkg/actors/fake/,pkg/channel/fake/,pkg/outbox/fake/,pkg/security/fake/,pkg/runtime/mock/) contain in-package fakes used for unit testing. These are co-located with the production code rather than in a separatetests/directory, making them easy to discover and maintain.tests/directory at repo root for integration/e2e: End-to-end and integration tests are cleanly separated from unit tests in a top-leveltests/directory with its ownrunner/infrastructure for standing up real Kubernetes clusters. Thetests/apps/directory contains full application binaries used as test subjects.