Dapr 1.19
We're excited to announce the release of Dapr 1.19!
The main changes in this release:
- Faster workflows, jobs and reminders. In the nightly performance tests against 1.18.0, workflow throughput is up to 40% higher. The p99 latency of actor reminder registration is 71% lower, and the p99 latency of Jobs scheduling is 33% lower. Workflow workers in the Python, Java, .NET and Go SDKs now get only the new events of each turn, not the full history.
- Workflows across apps. A workflow client can now start, get, raise events on, pause, resume, terminate, purge and rerun a workflow that another app owns. Access policies decide which app can do what. A new
requiresrule allows a schedule only when the caller's history contains the required upstream events. A workflow can also start a detached workflow that outlives it. - New building blocks (alpha). Binary Store stores large files in Amazon S3 and S3-compatible stores, Azure Blob Storage, Azure Data Lake Storage, Google Cloud Storage and OCI Object Storage. Search and Vector index and query documents and vectors, with Meilisearch components.
- Dapr MCP server (alpha). The Dapr MCP server gives AI agents and IDE assistants the building blocks of a sidecar as Model Context Protocol tools. It ships as a separate binary, on its own release cycle.
- Actors. With actor placement in the Scheduler (opt-in), each reminder goes straight to the host that runs the actor. The cluster then does not need the Placement service. New APIs list and get actor timers over HTTP and gRPC, and list reminders over HTTP. When an actor moves to another host, the old host deletes its timers, so they no longer fire twice.
- Kafka transactions. Kafka pub/sub can make a bulk publish atomic, read only committed records, and run consume-transform-produce in one transaction. All three are opt-in.
- Operations. Logs can go to several destinations, with file rotation and a configurable timestamp format. Workload identity certificates carry the image references of the pod. Every Kubernetes Service that Dapr creates sets
appProtocolfor service meshes. - Security. Five security fixes. Four of them, for service invocation, the Scheduler and workflows, also shipped in 1.18.6. The fifth makes the Operator enforce app scopes and configuration assignment, and it also shipped in 1.18.9 and 1.17.18. Four of the five change behavior.
Read Breaking Changes and Deprecation Notices before you upgrade. 1.19 contains behavior changes that can affect an upgrade, mostly in the SDKs.
Thanks to all the new and existing contributors who helped make this release happen.
If you're new to Dapr, visit the getting started page and familiarize yourself with Dapr.
The docs have been updated with all the new features and changes of this release. To get started with new capabilities introduced in this release, go to the Concepts and the Developing applications.
Go to the upgrading Dapr section for steps to upgrade to version 1.19.
Acknowledgements
Thanks to everyone who made this release possible!
@acroca, @adam6878, @Advait2912, @anneheartrecord, @anxkhn, @arturotrenard, @baltasarblanco, @CasperGN, @cicoyle, @DamienCassou, @famarting, @gargsajal9, @GHX5T-SOL, @icmp0x8, @ihopenre-eng, @javier-aliaga, @jjcollinge, @jongep86, @JoshVanL, @jslatten, @kayvonkhosrowpour, @kshitizj03, @LiBaoxuan-Neil, @LilDojd, @LindseyZ1205, @lrascao, @m3nax, @magic-peach, @manduinca, @marcduiker, @matheusandre1, @mikeee, @MrMint, @MsfPablo, @mtaghavi2005, @Mukuwul, @MyMirelHub, @nelson-parente, @olitomlinson, @pablochacin, @passuied, @Psingle20, @pujitha24, @RakeshCodeLab, @Rishabh-git10, @SaiPisey2, @SarthakB11, @seherv, @sicoyle, @siri-varma, @somaz94, @stywzn, @tezizzm, @vip892766gma, @WhitWaldo, @yaron2, @Yash121l
Highlights
These are the v1.19 release highlights:
Faster workflows, jobs and reminders
Compared with the published v1.18.0 run, the nightly performance tests on master show:
- Workflows: throughput is 40% higher in
TestWorkflowWithConstantVUsand 32% higher inTestSeriesWorkflowWithMaxVUs. - Jobs scheduling: p99 latency is 33% lower (39.5 ms to 26.3 ms), and the test now sustains the full requested 1000 QPS (921 QPS on 1.18.0).
- Actor reminder registration: p99 latency is 71% lower (148 ms to 43 ms), at 43% more registrations per second.
- Configuration subscribe: throughput is 67% higher over HTTP and about 2.8x over gRPC. This test varies up to 3x between runs, so treat the gRPC figure as indicative.
Service invocation, state and pub/sub publish show no change beyond run-to-run noise. The figures are medians of 8 runs from 23/09/2026 to 02/10/2026, on the same cluster as the v1.18.0 run.
Changes in this area include:
- Event-driven completion of work items.
- Cached tag maps for metrics on hot paths.
- Fewer state copies and event marshals per workflow turn.
- A separate size and payload-ratio aggregation for each meter.
- Large fan-outs: an empty-inbox wake-up reloads the workflow state only when its cache is stale. Before, each such wake-up re-read the whole history.
For workflows that run for minutes or hours, the workflow block of the metrics settings in Configuration now takes its own latencyDistributionBuckets, with a latencyDistributionUnits such as 1s. The workflow and activity execution latency histograms then use buckets that fit those durations, instead of the shared millisecond buckets, where every long workflow landed in the top bucket. The repository also ships Grafana dashboards for workflows and for the Scheduler in grafana/: execution and activity rates, latency percentiles, failures, client operations and payload size against the limit, which no dashboard charted before. The etcd panels of the Scheduler dashboard need --etcd-metrics=extensive.
The 1.19 charts are published after the GA tag on the performance results page.
Workflow workers get only the new history
Long-running workflows now spend less time on each turn. Before 1.19, a workflow worker received the full history of an instance on every turn. For long-running instances, sending and parsing that history took most of the time of each turn.
A worker can now advertise the WORKER_CAPABILITY_STATEFUL_HISTORY capability on its work-item stream. The worker then keeps the history of each instance in a cache. When the worker already has the history from an earlier turn on the same stream, the sidecar sends only the new events. The worker builds the full history from its cache and the new events, so the sidecar no longer re-sends, and the worker no longer re-parses, the whole history on every turn. On a reconnect the sidecar sends the full history. If the worker has evicted the instance from its cache, it fetches the full history from the sidecar. Either case adds latency, but it does not change the result.
The protocol is in durabletask-go#110. The SDKs that support it turn it on by default:
| SDK | Stateful history |
|---|---|
| Python | On by default. To turn it off, set disable_stateful_history=True on WorkflowRuntime. |
| Java | On by default. To turn it off, call WorkflowRuntimeBuilder.withStatefulHistoryDisabled(true). |
| .NET | On by default. To turn it off, set WorkflowRuntimeOptions.DisableStatefulHistory. |
| Go | On by default from go-sdk v1.16.0 (durabletask-go v0.15.0). The Go SDK has no switch to turn it off; client.WithStatefulHistoryDisabled() in durabletask-go does. |
| JavaScript | No. The new JavaScript workflow engine does not use the shared DurableTask client library. |
Health pings on idle work-item streams
On an idle work-item stream, the sidecar now sends a health ping every 30 seconds to a worker that advertises the WORKER_CAPABILITY_HEALTH_PING capability. Load balancers such as AWS ALB and nginx close an idle stream after 60 seconds, and before 1.19 that cost the worker a reconnect and a full history resend. The 1.19 Python, Java and .NET SDKs and durabletask-go v0.15 (Go SDK 1.16) advertise the capability. Set DAPR_WORKFLOW_HEALTH_PING_INTERVAL on daprd to change the interval.
WorkflowsFastPath preview feature
The new WorkflowsFastPath preview feature is off by default. With it, a workflow wake-up runs on the host that armed it, instead of through a scheduler reminder for each event. A repeating janitor reminder for each instance keeps the work durable.
The fast path stays off when a scheduler-enforced workflow or activity concurrency limit is configured, and daprd logs the reason. Fast-path drives run work items directly on the sidecar, so they would bypass the concurrency limit of the scheduler.
Workflows across apps
A workflow client can now run its operations on a workflow that another app in the same namespace owns: start, get, raise event, pause, resume, terminate, purge and rerun. Listing instance IDs and reading history stay local. Use this when one app manages workflows that another app owns, for example an API or operations service that starts and inspects order workflows owned by the orders app, without registering those workflows itself. Before 1.19, a workflow could already start child workflows and activities in another app, but the client operations worked only on workflows of the calling app.
The WorkflowAccessPolicy of the target app decides which operations a caller can do, per operation and per workflow name. The workflow request protos have a new optional app_id field, and the HTTP endpoints accept an appID query parameter. Rerun is available through the SDK workflow clients only. The engine side is in durabletask-go#117. When no workflow worker is connected for the target app, local or remote, these operations now fail at once with a clear error instead of a 20 second retry and an actor routing error (see Breaking Changes).
Workflow access policy requires, detached workflows, duplicate instance IDs and child retries
- A
WorkflowAccessPolicyrule can now have arequiresblock. The operation is then allowed only when the propagated workflow history of the caller contains the listed events. A rule can require proof that the caller saw a specific upstream event, instead of allowing the caller unconditionally. For example, a billing app can allow itschargeactivity only for callers whose history holds anevent.raisednamedorder.validatedfrom the orders app, so a caller cannot skip the validation step.requiresis an ordered list of up to 20 entries, each withappID,eventType(activity.started,activity.completed,workflow.started,workflow.completedorevent.raised) andname. It applies to scheduling only: activity rules, or workflow rules whose only operation isschedule. - A workflow can now start a detached workflow. A detached workflow is an independent instance, with no link to its parent and no result back to it. In durabletask-go, the method is
WorkflowContext.ScheduleNewDetachedWorkflow. Use it when a workflow needs to start work that should outlive it, such as a clean-up or report job, without waiting for the result. Before 1.19, the workaround was a client call inside an activity. - Scheduling through an SDK workflow client fails with the gRPC
AlreadyExistsstatus code when the instance ID belongs to an active (not completed) instance (in the sidecar since 1.18.2). The error message does not change, so an SDK can detect the conflict without parsing the message, and a client can start a workflow with a fixed instance ID as an idempotent call and treatAlreadyExistsas already running. A completed instance ID is reused by default; it also returnsAlreadyExistswhen the client setsWithEnforceUniqueInstanceIDor when the old instance's child workflows have not finished. The Dapr runtime workflow API (HTTP and gRPCStartWorkflowBeta1) keeps its error response. - A child workflow that runs as a retry attempt now records the instance ID of the first attempt in the parent's history. Each retry of a child workflow is a separate instance with its own ID, so tooling that reads a parent's history can now group the attempts of one call without walking the retry timers between them.
Placement served by the Scheduler (opt-in)
With this feature on, the Scheduler places actors itself, and it sends each actor reminder straight to the host that runs the actor. With the standalone Placement service, a reminder goes to any instance of the app, and that instance forwards it to the owner. The cluster also no longer needs the Placement service. The feature is off by default. Applications and sidecars need no configuration change.
Before you turn it on, upgrade every sidecar to 1.19 or later. An older sidecar can use only the Placement service. Once no Placement service remains, its actor and workflow APIs stall until you upgrade its pod, and the Scheduler logs a warning. The older sidecar does not stop the Scheduler from serving the upgraded sidecars.
To turn it on, set this Helm value, and pass it on every later helm upgrade, because Helm resets values you do not pass:
:::yaml
global:
scheduler:
placement:
enabled: true # default: false
How it works:
- The Helm chart does not deploy the Placement StatefulSet, Service or RBAC. It starts the Schedulers with
--placement-enabled=true. The chart does not render unlessglobal.scheduler.enabled,global.actors.enabledandglobal.actors.serviceName=placementare set. - While a Placement service is still deployed, it stays the placement authority and the Schedulers do not serve placement. When the Placement pods are gone, the Schedulers detect it and take over within a few seconds — but the Schedulers also restart to pick up the new flag as part of this same upgrade, so expect actor and workflow activity to pause for longer than that while the Schedulers come back up.
- You can turn the feature on or off without sidecar restarts. When you turn it off, the Placement service is redeployed and sidecars move back to it. Sidecars switch as soon as the Placement pod exists, so expect a short pause until it is ready.
- Actor state is not lost. The two services place actors differently, so actors are deactivated and reactivated on their new hosts once per switch, in either direction.
- The Scheduler needs
get,listandwatchonpodsin the Dapr namespace to detect a Placement service. The chart adds this as thedapr-scheduler-podsRole. If you use custom RBAC, add it before any 1.19 upgrade.
To check which authority a sidecar uses, look for Connected to scheduler placement leader <address> in its log. The other authority logs Connected to placement <address>. In the Scheduler, dapr_scheduler_placement_leader and dapr_scheduler_placement_streams_connected show the leader and the connected sidecars, and dapr_scheduler_placement_incapable_sidecars counts sidecars older than 1.19.
New flags: daprd --actors-placement-startup-timeout (default 30s, annotation dapr.io/actors-placement-startup-timeout), and Scheduler --placement-enabled, --placement-disseminate-timeout (default 8s) and --placement-disseminate-coalesce-window (default 0). The two --placement-disseminate-* flags have no Helm value.
In self-hosted mode, use dapr init --scheduler-placement. It is not available with -k or --slim. It does not start the dapr_placement container, and it starts dapr_scheduler with --placement-enabled=true.
Binary Store building block (alpha)
A new building block stores files through one API, for content that is too large for a state store. Create a component of a binarystore.* type and call the alpha API:
- HTTP:
/v1.0-alpha1/binarystore/{name}/{fileName}. UsePUTorPOSTto write a file,GETto read it andDELETEto delete it. - gRPC:
SetBinaryFileAlpha1streams a file in,GetBinaryFileAlpha1streams it out, andDeleteBinaryFileAlpha1deletes it.
Components: binarystore.aws.s3 (Amazon S3 and S3-compatible stores), binarystore.azure.blobstorage (v1-19.docs.dapr.io), binarystore.azure.datalake (v1-19.docs.dapr.io), binarystore.gcp.bucket (v1-19.docs.dapr.io), binarystore.oci.objectstorage (v1-19.docs.dapr.io), and binarystore.in-memory for tests.
SDK support in 1.19: .NET (via Dapr.BinaryStore) and JavaScript (@dapr/dapr). The Go, Python, and Java SDKs do not support it in 1.19, so call the HTTP or gRPC API directly. Docs: Binary Store, .NET SDK and JS SDK
Proposal: proposals#88.
Search building block (alpha)
A new building block lets an application store, retrieve and query documents using full-text search engines through one API, whatever the store behind it
Components: search.meilisearch, and search.in-memory for tests.
SDK support in 1.19: .NET (via Dapr.Search (www.nuget.org)) and JavaScript (@dapr/dapr). The Go, Python, and Java SDKs do not support it in 1.19, so call the HTTP or gRPC API directly.
Docs: Search and the Search API
Proposal: proposals#107.
Vector building block (alpha)
A new building block provides a means to store, retrieve and run similarity queries over dense vectors/embeddings in vector databases through a single API one at a time or in a batch.
Components: vector.meilisearch, and vector.in-memory for tests.
SDK support in 1.19: .NET (via Dapr.Vector (www.nuget.org)) and JavaScript (@dapr/dapr). The Go, Python, and Java SDKs do not support it in 1.19, so call the HTTP or gRPC API directly.
Docs: Vector and Vector API references.
Proposal: proposals#107.
Dapr MCP server (alpha)
The Dapr MCP server (dapr/dapr-mcp-server) is a standalone Model Context Protocol server, written in Go, that runs next to a Dapr sidecar and turns its building blocks into MCP tools. Any MCP client can call them: Claude Desktop, Cursor, Claude Code, VS Code, Dapr Agents, or your own agent.
The MCP server is a separate binary in its own repository, with its own version numbers and release cycle, and it is in alpha, so tool names, inputs and configuration can still change.
How it works:
- The server connects to the sidecar over gRPC with the usual settings,
DAPR_GRPC_PORTandDAPR_GRPC_ENDPOINT. It retries five times, then exits. - It reads the sidecar's metadata and registers tools for every building block that has at least one component loaded.
get_components,invoke_serviceandinvoke_actor_methodare always registered. - It serves MCP over stdio by default, for clients that launch it themselves, or over streamable HTTP with
--http. Authentication, health endpoints and CORS apply to the HTTP transport only. - Tools follow component hot reloading. Adding the first component of a type registers that type's tools, removing the last one takes them away, and connected clients are told that the list changed. A client that reads the tool list only once has to reconnect to see it.
The tools cover state including transactions, pub/sub, output bindings, secrets, service invocation, actors, distributed lock, cryptography and conversation. Each one carries the MCP safety annotations readOnlyHint, destructiveHint and idempotentHint.
Authentication is off until you set AUTH_MODE, which takes oidc, spiffe, dapr-sentry or hybrid. Turn it on whenever you serve over HTTP to anything other than localhost. The server can reach whatever its sidecar can reach, and it returns tool results to the model, including the values from get_secret and get_bulk_secrets, so scope its components and secrets to what the agent needs.
Telemetry is off until you set an OTLP endpoint. Over HTTP the server also serves /livez, /startupz and /readyz health endpoints.
Actor timer and reminder APIs, timer ownership and activation ID
Actors get APIs to read their timers and reminders:
- gRPC:
ListActorTimersandGetActorTimer. - HTTP:
GET /v1.0/actors/{actorType}/{actorId}/timersandGET /v1.0/actors/{actorType}/{actorId}/timers/{name}. - HTTP:
GET /v1.0/actors/{actorType}/{actorId}/reminders, to match the gRPCListActorRemindersAPI.
Before 1.19, timers could not be read back at all, and reminders could be listed only over gRPC. Use the new APIs to check why a timer did not fire, or to build tooling that shows what an actor has scheduled.
When an actor moves to another host, its in-memory timers on the old host are now deleted. Before 1.19, the old host kept firing them, and the actor ran twice when the timer was registered again on the new host. A timer operation sent to a host that does not own the actor now fails with ERR_ACTOR_TIMER_NOT_OWNED (HTTP 403, gRPC PermissionDenied). A timer fire that was parked during a placement change, and whose timer the ownership sweep deleted, is dropped and counted in timers_dropped_total.
daprd now sends a Dapr-Actor-Activation-Id header on the invoke, reminder and timer callbacks to the app, and the same key as metadata on the gRPC actor callback stream. The ID is new each time daprd activates the actor, so an SDK can drop an actor object it kept from an earlier activation instead of reusing its cached state, for example after daprd deactivated the actor on its idle timeout and activated it again on the same host. No SDK uses the header in 1.19. The Go SDK change is go-sdk#846.
Image references in workload SVIDs
Workload identity certificates now record which images run in the pod. A consumer can use this to link an mTLS identity or an attestation record to the exact image that ran. For example, it can find the workloads that run an image with a known CVE. On Kubernetes, Sentry now adds the image references of the requesting pod's containers (the app containers and daprd) to the workload identity certificate. Sentry stores them in a non-critical X.509 extension, as a list with one entry per container: the image as written in the pod spec and, when the container has already started, its digest. Sentry takes the image data from the pod object that the Kubernetes validator already reads, through its pod cache or the API server, not from the request. The pod cache now holds only pods with the dapr.io/sidecar-injected label.
appProtocol on Kubernetes Services
Every Kubernetes Service that Dapr creates now sets appProtocol on each port. This includes the control-plane Services of the Helm chart and the sidecar Service that the operator creates for each app. A service mesh such as Istio can then select the protocol from this field instead of protocol sniffing. Ports that carry gRPC inside Dapr mTLS are declared tls, not grpc, so a mesh does not read the encrypted bytes as plain HTTP/2.
Kafka pub/sub transactions
Kafka pub/sub gets transactions. Both modes are off by default:
producerTransactionsEnabled: every publish, single or bulk, runs in a Kafka transaction on an idempotent producer. A bulk publish is then atomic: all entries commit or none do. The guarantee is atomicity per publish. There is no transaction recovery or fencing across component restarts. The mode needsproducerRequiredAcks: "all",producerRetryMaxof 1 or more, and Kafka 0.11 or later. It lowers publish throughput.consumerIsolationLevel: "read_committed": a subscription reads only committed records. It never sees records from open or aborted transactions.consumerTransactionsEnabled: each delivery runs inside a transaction (consume-transform-produce). The outputs of a delivery and its offset commit together, and failed attempts are invisible toread_committedconsumers. Side effects outside Kafka, such as database writes, are not covered. The mode needs a consumer group, the sameproducerRequiredAcksandproducerRetryMaxsettings, and Kafka 2.5 or later.
Components
Pub/sub:
- RabbitMQ: externally managed and consistent-hash exchanges. Two new metadata options,
exchangeDeclareModeandqueueDeclareMode, eachdeclare(the default) orpassive. Inpassivemode, the component expects the exchange or queue to already exist, instead of creating it. The component also accepts thex-consistent-hashexchange kind, for hash-based partitioning across queues. - Generic AMQP 1.0 pub/sub. The AMQP 1.0 component now also registers as
pubsub.amqp. This form has no vendor-specific address prefix, so it works against any AMQP 1.0 broker.pubsub.solace.amqpkeeps its originaltopic://andqueue://prefixes. Existing Solace components keep working unchanged. anonymousis now honored overamqps://, so a client certificate can be the only credential (mutual TLS without a username/password).- Publishing with
ttlInSecondsno longer panics the sidecar, a lost connection reconnects with backoff, and a failed link no longer closes the shared connection. - Subscriptions can set
subscriptionName,durable,sharedandselector, so a named subscription can be durable, shared across replicas and filtered by the broker. New component settings:containerID,durableMessagesandapplicationPropertiesFromMetadata.
Secret stores:
- HashiCorp Vault: native Kubernetes auth. Set
vaultAuthMethod: kubernetes, and the component logs in to Vault with the pod's service account token. It no longer needs the Vault Agent Injector sidecar to get a token.vaultAuthMethod: tokenworks as before.
Conversation:
- Conversation API:
max_tokens. A Conversation API request can now cap how many tokens a call generates. Setmax_tokenson the request, ormaxTokensin the component metadata as a default. A request value greater than zero overrides the metadata default. - OpenAI conversation: opt-in Responses API. Set
useResponsesAPI: "true"in the OpenAI component metadata, and the component calls/v1/responsesinstead of Chat Completions. Reasoning models that reject function tools on Chat Completions can then call tools. The setting is off by default, and it does not work withapiType: azure.
Structured logging: more output destinations and file rotation
The control-plane binaries and daprd take six new logging flags, from two dapr/kit changes:
--log-outputs: a comma-separated list of log destinations (stdout,stderr, or a file path). It merges with--log-file, so an existing--log-fileconfiguration is unchanged.--log-file-max-size,--log-file-max-backups,--log-file-max-ageand--log-file-compression: rotation for file destinations. Without them, a file destination is a plain file that grows with no limit.--log-timestamp-format: a Go time layout for the log timestamp. The default, RFC3339 with nanoseconds, stays unless you set this flag.
All six flags default to off or empty, so a binary that sets none of them behaves as before. When rotation is on and no size is set, a file rotates at 100 MB. The sidecar injector has no annotation for these flags. See log destinations and file rotation.
See the full list of changes below for the rest.
SDK Improvements
Go SDK
Workflows: the workflow client lists instances, reads the history of an instance and reruns a workflow from an event (ListInstanceIDs, GetInstanceHistory, RerunWorkflowFromEvent). A new example and a section in the client guide show how to use them.
Workflows: WorkflowContext.Select waits for the first of several tasks to complete and returns its index, the WhenAny that the other SDKs already had (in durabletask-go v0.15.0, which go-sdk 1.16 pins). Use it for an approval gate that waits for Approve, Reject or a timeout timer, whichever comes first. Before, the only way was to poll each event with short WaitForSingleEvent timeouts, and every poll added a timer and a history entry, so a workflow parked at a gate grew its history without bound. Select adds no timers or history entries, and the losing tasks stay pending to be awaited or selected later.
.NET SDK
The v1.19 release of the Dapr .NET SDK continues the move toward focused, building-block-specific packages. New clients include Dapr.BinaryStore for streaming binary uploads and downloads, alongside Dapr.Search and Dapr.Vector for the new alpha search and vector APIs. Each includes source generators for strongly typed clients.
This release introduces Dapr.Actors.Next, a new actor programming model alongside the existing Actors SDK, with generated proxies and registration, constructor injection, state schema migration, built-in state machines, and deterministic testing. In .NET 10 in-process benchmarks measuring client-side overhead (not end-to-end actor execution), proxy creation was approximately 38× faster and SDK-only invocation 10× faster, with 99% and 97% fewer allocated bytes, respectively, than the existing Dapr.Actors SDK.
The new Dapr.Messaging package provides Native AOT-compatible, strongly typed publish/subscribe support with generated message handlers. It supports streaming subscriptions, HTTP and gRPC push delivery, bulk messaging, content-based routing, and dead-letter topics.
Workflows gain opt-in large-payload offloading through Binary Store, detached workflow scheduling, and history caching with delta work items to reduce repeated transfers. In a benchmark available in the repository using a 2 MB document, explicit data references roughly halved total workflow completion time and reduced managed allocations by 66% compared with inline payloads, with history caching enabled. This release also improves workflow tracing, versioning, and connection reliability.
Finally, the Jobs client adds gRPC transport alongside HTTP, timezone-aware scheduling, and job listing and purging. New transactional outbox helpers simplify pairing state changes with published events, and the SDK adds .NET 11 preview support.
Do note that in the next v1.20 release, support for .NET 8 and 9 will be dropped as they will no longer be supported .NET frameworks as of November 2026.
There were 69 merged PRs since the .NET SDK v1.18.1 was released.
A huge thank you to everyone that filed an issue, opened a PR or otherwise reached out on Discord regarding your experience using the JS SDK and how it could be improved!
General
- ADDED Support for .NET 11 preview (#1891).
- UPDATED Improved gRPC method discovery and API-version failover, with bounded reflection discovery, source-generated capability information, and caching of successful fallback methods (#1920).
- FIXED
Dapr.Commonis now transitively referenced by consuming packages, avoiding the need to install it separately when using packages such asDapr.SecretsManagement(#1852). - FIXED Propagate trace context on gRPC calls so sidecar spans retain the expected parent-child relationship with application operations (#1858).
Actors
- UPDATED Refresh actor state tracking in place after reentrant calls, avoiding a performance regression in reentrancy handling (#1912).
- UPDATED Cache missing actor-state entries to avoid repeated runtime lookups for absent keys (#1913).
- UPDATED Improve actor-state write performance by removing preliminary runtime existence checks when setting state (#1914).
- FIXED Synchronize cached
NotFoundentries after a reentrant save so newly persisted state becomes visible to the default tracker (#1916). - FIXED Preserve actor turn-based concurrency when an invocation is canceled while its handler is still running (#1937).
- FIXED Mark actor-state changes clean only after persistence succeeds, ensuring failed or canceled saves do not silently lose writes on retry (#1946).
Actors.Next
- ADDED Introduced
Dapr.Actors.Next: an alternative actor SDK using app-initiated bidirectional gRPC streams, source-generated clients and dispatch, pluggable serialization, state migration, state machines, pub/sub-driven actors, dynamic invocation, analyzers, and a deterministic in-memory testing runtime. It requires Dapr runtime 1.18 or later and is not an API-compatible, drop-in replacement forDapr.Actors(#1865). - ADDED Support for actor reminder retry/failure policies (#1872).
- ADDED Per-actor-type runtime configuration overrides for settings such as idle timeout, draining, and reentrancy (#1879).
- ADDED Get/list actor timer APIs, with corresponding scheduler support and an example (#1949).
- UPDATED Mark internal Actors.Next component projects as non-packable so they are not independently published (#1868).
- UPDATED Runtime options are now nullable and unset by default, allowing Dapr runtime defaults to apply unless explicitly overridden (#1903).
- UPDATED Reuse the streaming pub/sub implementation from
Dapr.Messaginginstead of maintaining a separate implementation (#1907). - UPDATED Add regression coverage demonstrating that same-activation reentrant invocation works correctly (#1911).
- UPDATED Apply missing-state caching improvements to Actors.Next (#1931).
- FIXED Correct aggregate-package construction and packaging smoke tests, and introduce more specific exception types (#1869).
- FIXED Prevent duplicate subscription descriptors from causing later actor registrations to replace earlier registrations (#1930).
- FIXED Ensure the actor stream manager registers and starts when other
IHostedServiceimplementations are already registered (#1932). - FIXED Prevent cancellation of one caller from stranding accepted turns or masking an actor's original exception (#1936).
- FIXED Harden concurrency, reentrancy, mailbox scheduling, stream recovery, activation/deactivation, state persistence and migration, state-machine behavior, timer/reminder lifetimes, and generated code; also reduce generator memory consumption (#1938).
Pub/Sub and Messaging
- ADDED Complete the
Dapr.Messagingimplementation for all three Dapr pub/sub modes, providing a dedicated alternative to the pub/sub functionality inDapr.ClientandDapr.AspNetCore, with analyzers, code fixes, and examples (#1906). - UPDATED Centralize CloudEvent constants in
Dapr.Clientand reuse them in transactional outbox helpers (#1889). - FIXED Improve streaming subscription error handling and reconnection, expose subscription faults through a completion task, and ensure re-subscription works after termination (#1888).
State Management and Transactional Outbox
- ADDED Convenience APIs for composing state transactions using Dapr's native transactional outbox, including metadata constants, fluent projection/CloudEvent helpers, and an
OutboxTransactionBuilderthat enforces matching state/projection keys (#1863).
Bindings
- FIXED Exclude binary gRPC metadata from
InvokeBindingcalls to avoid failures against affected runtimes, while retaining trace propagation through text headers (#1901).
Cryptography
- FIXED Resolve a race condition during encryption and decryption (#1929).
Service Invocation
- ADDED An overload accepting gRPC channel options when creating an invocation client (#1921).
- ADDED A standalone gRPC proxy invocation sample demonstrating calls through Dapr sidecars, deadlines, cancellation, and error handling (#1927).
Jobs
- ADDED Time-zone configuration when scheduling jobs through the builder, scheduler, or raw Cron expression APIs (#1884).
- ADDED gRPC job callbacks alongside HTTP callbacks, sharing the same handler implementation (#1886).
- ADDED List jobs and purge jobs by prefix or across all jobs, with an updated example (#1890).
- UPDATED Align Jobs gRPC methods and callbacks with their promotion to stable APIs; also refresh runtime protos and adjust release testing (#1928).
Workflows
- ADDED Stateful-history delta support: workers cache committed history and reconstruct subsequent turns from deltas, with bounded caching and full-history recovery on a cache miss (#1862).
- ADDED Support for executing and versioning workflows derived from generic base classes (#1885).
- ADDED An interface for
WorkflowStateto simplify mocking and testing without changing existing method return types (#1887). - ADDED Detached workflows, allowing a workflow to start another workflow without establishing a parent-child relationship (#1919).
- ADDED Health-ping support on the workflow client stream (#1922).
- ADDED Binary Store integration through
Dapr.Workflow.BinaryStore, enabling workflow data references instead of carrying payloads inline (#1934). - UPDATED Improve stateful-history caching with constant-time LRU eviction, configuration validation, and expanded concurrency, stream-isolation, and recovery coverage (#1917).
- UPDATED Reduce allocations in workflow data-reference handling and remove assumptions about replica affinity in caching (#1940).
- FIXED
GetWorkflowStateAsyncconsistently returns aWorkflowState, including for nonexistent workflows, and no longer logs an error for an ordinary not-found result (#1847). - FIXED Correct workflow-versioning registration-order behavior and expand regression coverage (#1850).
- FIXED Remove analyzer syntax requiring newer immutable collection APIs to resolve analyzer compatibility warnings (#1851).
- FIXED Downgrade analyzer dependencies to a compatible Roslyn version to restore workflow registration (#1854).
- FIXED Restore workflow trace propagation and add end-to-end observability coverage using Zipkin through
Dapr.Testcontainers(#1870). - FIXED Propagate unexpected errors when retrieving workflow state rather than swallowing exceptions other than
NotFound(#1877). - FIXED Recover the execution ID from workflow history when absent from the request, preventing deterministic task-ID collisions that could stall recreated workflow instances (#1880).
- FIXED Handle abstract workflow classes and additional generic/inheritance cases correctly in workflow generation (#1902).
- FIXED Address workflow implementation issues and generator/analyzer edge cases, including compatibility fixes for tests against Dapr 1.17 (#1942).
Binary Store
- ADDED A dedicated
Dapr.BinaryStoreSDK package for the Binary Store building block (#1933). - ADDED An example demonstrating Binary Store usage (#1935).
Search
- ADDED A dedicated
Dapr.Searchpackage with a client, source-generated typed indexes, an example, and a Meilisearch-backed Testcontainers harness (#1944).
Vector
- ADDED A dedicated
Dapr.Vectorpackage with a client, source-generated typed collections, an example, and integration-testing support (#1945).
Dependencies and Security
- FIXED Upgrade the transitive SSH.NET dependency to a patched version addressing GHSA-q939-rpr3-3284 (#1881).
- FIXED Update
Microsoft.SourceLink.GitHubfrom10.0.300to10.0.303to address a dependency security issue (#1905).
Miscellaneous / Testing / CI
- ADDED Automatically open or update a tracking issue when release/publish CI fails (#1864).
- ADDED Pass environment variables into the
daprdcontainer throughDapr.Testcontainers(#1871). - ADDED Support the
edgeruntime version in the test matrix and supporting utilities (#1943). - ADDED Configure the app-channel address in
Dapr.Testcontainers, enabling communication with an app container through its network alias on a shared Docker network (#1947). - UPDATED Migrate legacy integration and end-to-end tests from Kubernetes-based setup to the modern Testcontainers harness (#1941).
- UPDATED Split framework-specific test matrices to stay within GitHub Actions' 256-job limit (#1951).
- FIXED Correct runtime-version selection for GitHub Actions testing (#1855).
- FIXED Restore Dapr 1.17 CI coverage after multi-architecture runtime publishing resumed (#1856).
- FIXED Prevent stale sidecar endpoints after app-first startup retries by prioritizing newly assigned port overrides (#1896).
- FIXED Resolve a stalled packaging smoke test (#1939).
- FIXED Adjust Jobs failure-policy and version-compatibility integration tests. This was a direct commit rather than a PR (
6345bb03).
Python SDK
- Workflows: the worker supports stateful history and turns it on by default. To turn it off, set
disable_stateful_history=TrueonWorkflowRuntime. To tune the cache, usehistory_cache_ttl,history_cache_max_instancesandhistory_cache_max_bytes. - Workflows: client operations on workflows in other apps, list, history and rerun operations on the workflow client, and a health ping on the client stream.
- Workflows: orchestrator work items run on their own thread pool. Before, sync activities that schedule workflows could take every thread and deadlock the worker.
- Workflows: the worker recovers after a host sleep or network change leaves its sidecar connection half-open. Results of work items that run across a reconnect are sent on the new connection, so the sidecar no longer re-runs those activities.
- Workflows:
when_allwaits for every task before it reports the first failure. - Workflows: workflow gRPC channels honor
DAPR_GRPC_MAX_INBOUND_MESSAGE_SIZE_BYTESfor sending and receiving, so payloads over 4 MiB no longer fail withRESOURCE_EXHAUSTED. You can also passmax_grpc_message_lengthtoWorkflowRuntimeand to the sync and asyncDaprWorkflowClient. - Actors: with reentrancy on, reminders, timers and activation no longer read stale state after a reentrant call saves it. Actor state also needs fewer state store reads: missing keys are cached, and setting state skips the existence check.
- Pub/sub: per-message metadata in bulk publish (
publish_events) through the newBulkPublishEntrytype, exported fromdapr.clients. - Pub/sub: a streaming subscription returns the next message after a reconnect instead of
None.next_message()and iteration now raise the newStreamReconnectErrorafter five failed reconnects. See Breaking Changes. - Pub/sub: several wildcard subscriptions can be registered when topic validation is disabled.
- Configuration:
DAPR_*environment variables are read when a setting is used, not whendapris imported, so variables set later, for example by python-dotenv, take effect. - Clients: each sidecar health check attempt has its own timeout within
DAPR_HEALTH_TIMEOUT. A port that accepts connections but never replies no longer blocks client creation. - Clients: absolute unix socket endpoints such as
unix:///tmp/dapr.sockwork forDaprClient,WorkflowRuntimeandDaprWorkflowClient. - Clients: on macOS, the SDK sets
GRPC_DNS_RESOLVER=nativewhen you have not set it, which fixes "DNS query cancelled" errors. - Legacy
http://andhttps://gRPC endpoints now emit aDeprecationWarning. See Deprecation Notices. - New extensions: durable RAG and durability for Databricks Lakeflow.
- The extensions are now extras of the core
daprpackage. See Breaking Changes.
Java SDK
- Workflows: the worker supports stateful history and turns it on by default. To turn it off, call
WorkflowRuntimeBuilder.withStatefulHistoryDisabled(true). - Workflows: client operations on workflows in other apps, list, history and rerun operations, and a health ping on the client stream.
- Workflows: a
WorkflowInstanceAlreadyExistsExceptionwhen you schedule a workflow with the instance ID of an active instance. WorkflowRuntime.close()no longer blocks on an open work-item stream.- Workflows: the worker calls the sidecar's
HelloRPC every 30 seconds, so load balancers that ignore HTTP/2 PING frames, such as AWS ALBs, do not close the idle work-item stream. It is on by default. Setdapr.workflows.runtime.app.keep.alive.enabledtofalseto turn it off, or change the interval withdapr.workflows.app.keep.alive.interval.seconds. - Actors: timers and reminders take a number of repetitions and a TTL. Bulk subscriptions trace each entry.
- Spring Boot 4.0. See Breaking Changes.
- Testcontainers: build the Dapr
Configurationresource in code, with mTLS, logging, metrics, name resolution, components, secrets and an HTTP pipeline. ASubscriptiontakesscopes, andDaprContainergets default settings for Spring Boot apps.
JavaScript SDK
The v3.19 release of the Dapr JavaScript SDK features a complete rewrite of workflow support, removing the DurableTask dependency and adding configurable retries, patch-based versioning, cross-application workflows and activities, and detached workflows.
Workflow history can now be inspected, propagated to downstream workflows and activities, and used to rerun workflows from a specific event. Replay-safe logging, OpenTelemetry tracing, and improved worker recovery make long-running workflows easier to operate and troubleshoot.
The SDK adds support for the alpha Binary Store, Search, and Vector APIs, including opt-in offloading of large workflow payloads to binary storage. Conversation Alpha2 support brings tool calling, structured responses, token-usage reporting, and configurable token limits.
The Jobs and bulk publishing clients now use stable APIs while retaining compatibility with older runtimes. PubSub also gains alpha gRPC streaming subscriptions that require no application callback server, alongside improved failure handling that requests retries rather than acknowledging failed messages.
Additional improvements include HTTP encryption and decryption, bulk state deletion, expanded actor reminder management, custom serialization, and OpenTelemetry baggage propagation.
There were 61 merged PRs since the JavaScript SDK v3.18.0 was released.
A huge thank you to everyone that filed an issue, opened a PR or otherwise reached out on Discord regarding your experience using the JS SDK and how it could be improved!
General
- ADDED Pluggable serialization through
IDaprSerializer, retaining JSON as the default #893. - ADDED OpenTelemetry baggage propagation for outgoing HTTP and gRPC calls #900.
Actors
- ADDED Retrieve an individual registered actor reminder #901.
- ADDED List actor reminders by actor type, optionally filtering by actor ID #909.
- ADDED Bulk unregister actor reminders by actor type, optionally filtering by actor ID #912.
Binary Store
- ADDED Binary Store alpha API support over HTTP and gRPC, including streaming uploads and downloads #898.
Configuration
- ADDED Configuration API reference documentation covering retrieval and subscriptions to configuration changes #847.
Conversation
- ADDED Conversation Alpha2 support over HTTP and gRPC, including tool calling, structured responses, token limits, and usage metadata #919.
Cryptography
- ADDED HTTP encryption and decryption support #921.
Jobs
- ADDED Stable Jobs API support with legacy Alpha1 compatibility, job callbacks, and a fluent cron-expression builder #920.
- FIXED Job failure policies now accept omitted retry intervals and explicit
0simmediate retries, preserving omitted versus zero values across HTTP and gRPC #924.
Metadata
- UPDATED Centralized metadata lookups and runtime API-version selection in the metadata client #917.
PubSub
- ADDED Alpha gRPC streaming subscriptions without requiring an application callback server #922.
- UPDATED Bulk publishing now uses the stable HTTP and gRPC APIs while retaining compatibility with older runtimes #856.
- FIXED Subscription handler failures now request
RETRYrather than acknowledging messages withSUCCESS#923.
Search
- ADDED Search Alpha1 support over HTTP, including index management, document operations, and queries #927.
- ADDED gRPC implementation of the Search building block #929.
State Management
- ADDED Bulk state deletion over HTTP and gRPC #911.
- UPDATED Documentation and the hello-world example to clarify handling of missing state #848.
Vector
- ADDED Vector Alpha1 support over HTTP and gRPC, including collection management, vector storage, and similarity search #928.
Workflows
- ADDED Configurable retry policies for activities and child workflows #858.
- ADDED Health pings for the workflow worker’s gRPC stream #859.
- ADDED Workflow instance listing, execution-history retrieval, and rerunning workflows from a specific history event #885.
- ADDED Worker readiness signal #887.
- ADDED Cross-application task routing, history-propagation options, cancellation, and abort-signal support #888.
- ADDED Workflow and activity context accessors, typed state deserialization, and nested failure-detail access #894.
- ADDED Detached workflows that execute independently of the calling workflow #896.
- ADDED Protocol-supported activity execution IDs, including replay preservation and completion-event matching #897.
- ADDED Typed access to propagated workflow history, with queries by workflow name, application ID, and instance ID #899.
- ADDED Replay-safe workflow logging #903.
- ADDED Binary Store-backed workflow payload references and opt-in offloading of large payloads #905.
- ADDED OpenTelemetry workflow tracing, spans, and trace-context propagation #910.
- ADDED Patch-based workflow versioning through
isPatched#915. - UPDATED Rewrote the workflow implementation, removing the dependency on
@dapr/durabletask-js#857. - UPDATED
continueAsNewnow preserves unprocessed events by default, aligning with the .NET SDK #886. - UPDATED Workflow history and rerun documentation and tests, including missing-instance errors and replacement-input semantics #889.
- FIXED Work items were dropped when dispatch exceeded a fixed concurrency limit #861.
- FIXED Established stream failures no longer stop the workflow worker from reconnecting #863.
- FIXED Completion-handling race affecting workflow state when using
whenAny#890. - FIXED Workflow reliability issues involving task composition, replay-safe clocks and GUIDs, event handling, and completion-delivery recovery #908.
- FIXED Blocked activities no longer starve workflow work items #918.
- FIXED Recognize
edgeruntime builds as supporting workflow patches #925. - FIXED Preserve workflow IDs, task IDs, and completion tokens consistently in successful and failed work-item responses 6d7a59b (direct commit; no associated PR).
Miscellaneous / Testing
- UPDATED Protobuf definitions and generated bindings for Dapr 1.19 #891.
- UPDATED Runtime compatibility test matrix to include Dapr 1.17 #906.
- FIXED Pass the Codecov token to coverage uploads #916.
- FIXED Release publishing by using an npm version that supports OIDC trusted publishing #926.
Dependencies
- UPDATED
@grpc/grpc-jsto1.14.4#835. - UPDATED
undicito7.29.0#844. - UPDATED Go gRPC to
1.83.1in the gRPC proxy server example #850. - UPDATED
brace-expansionto1.1.21in the PubSub example #862. - UPDATED
shell-quoteto1.12.0#865. - UPDATED
handlebarsto4.7.10#867. - UPDATED
brace-expansionto1.1.21in the HTTP actor parking-sensor example #868. - UPDATED
brace-expansionto1.1.21in the gRPC proxy client example #869. - UPDATED
brace-expansionto1.1.21in the HTTP PubSub example #870. - UPDATED
brace-expansionto1.1.21in the gRPC cryptography example #871. - UPDATED Go gRPC to
1.83.2in the gRPC proxy server example #872. - UPDATED npm dependencies and development tooling #902.
- UPDATED
undefsafeandnodemon#904. - UPDATED
brace-expansionto1.1.21in the configuration example #907. - UPDATED
@opentelemetry/coreto2.8.0#913.
List of issues addressed in this release
v1.19.0-prs.md (github.com) lists the pull requests in this release. It is a separate file because GitHub limits the length of a release description. It covers the runtime, the CLI, the components, the Go, Java and Python SDKs, and the shared libraries kit and durabletask-go. The .NET SDK and JavaScript SDK sections under SDK Improvements list their own pull requests.
Documentation
See the v1.19 docs milestone.
Quickstarts
See the v1.19 quickstarts milestone.
Upgrading to Dapr 1.19
To upgrade to this release of Dapr, follow the steps below to ensure a smooth upgrade.
Local Machine / Self-hosted
Uninstall Dapr using the CLI you currently have installed. Note that this will remove the default $HOME/.dapr directory, binaries and all containers dapr_redis, dapr_placement, dapr_scheduler and dapr_zipkin, and the dapr_scheduler volume. Linux users need to run sudo if docker command needs sudo:
:::bash
dapr uninstall --all
Download the latest release from here and put the dapr binary in your PATH.
Once you have installed the CLI, run:
:::bash
dapr init --runtime-version=1.19.0
Use the full version, 1.19.0. The CLI puts the version string into download URLs, so a short form such as 1.19 does not resolve. dapr init without --runtime-version installs the newest GA runtime, never a release candidate.
Wait for the update to finish, then ensure you are using the latest version of Dapr (1.19.0) with:
:::bash
$ dapr --version
CLI version: 1.19.0
Runtime version: 1.19.0
To serve actor placement from the Scheduler on a self-hosted machine, run dapr init --scheduler-placement. The flag is for self-hosted mode only and needs runtime 1.19 or later. It does not work with -k or with --slim. It does not start the dapr_placement container, and it starts the dapr_scheduler container with --placement-enabled=true. dapr run needs no change. See Opt-in: Placement served by the Scheduler for what changes in a cluster.
Kubernetes
Upgrading from previous version
You can perform zero-downtime upgrades using both Helm 3 and the Dapr CLI.
Upgrade using the CLI
Download the latest release from here and put the dapr binary in your PATH.
To upgrade Dapr, run:
dapr upgrade --runtime-version 1.19.0 -k
To upgrade with high availability mode, set the chart value. dapr upgrade has no --enable-ha flag; only dapr init has it:
dapr upgrade --runtime-version 1.19.0 -k --set global.ha.enabled=true
dapr upgrade -k also applies the updated CRDs, when you pass the full version.
Wait until the operation is finished and check your status with dapr status -k.
Note: Make sure your deployments are restarted to pick the latest version of the Dapr sidecar.
Upgrade using Helm
Dapr 1.19 updates two CRDs: Configuration (new workflow latency-bucket fields in the metrics settings) and WorkflowAccessPolicy (the new requires field). helm upgrade does not update CRDs, so apply them first:
kubectl apply -f https://raw.githubusercontent.com/dapr/dapr/v1.19.0/charts/dapr/crds/configuration.yaml
kubectl apply -f https://raw.githubusercontent.com/dapr/dapr/v1.19.0/charts/dapr/crds/workflowaccesspolicy.yaml
If you upgraded from 1.17 with Helm and did not apply the 1.18 CRDs, also apply mcpservers.yaml from the same location:
kubectl apply -f https://raw.githubusercontent.com/dapr/dapr/v1.19.0/charts/dapr/crds/mcpservers.yaml
Then upgrade the chart:
helm repo add dapr https://dapr.github.io/helm-charts/
helm repo update
helm upgrade dapr dapr/dapr --version 1.19.0 --namespace=dapr-system --wait
To upgrade with high availability mode, add --set global.ha.enabled=true to the helm upgrade command.
Wait until the operation is finished and check your status with dapr status -k.
Note: Make sure your deployments are restarted to pick the latest version of the Dapr sidecar.
If you manage the RBAC of the Dapr control plane outside the Helm chart, grant the Scheduler get, list and watch on pods in the Dapr namespace (the chart's dapr-scheduler-pods Role), in addition to its namespaces permission. The Scheduler uses this to detect whether a Placement service is deployed. It needs the permission on every 1.19 upgrade, whether or not you turn on Placement served by the Scheduler. The Helm chart and dapr upgrade -k apply it for you.
Starting a fresh install on a cluster
See how to deploy Dapr on a Kubernetes cluster for a complete guide to installing Dapr on Kubernetes.
You can use Helm 3 to install Dapr:
helm repo add dapr https://dapr.github.io/helm-charts/
helm repo update
kubectl create namespace dapr-system
helm install dapr dapr/dapr --version 1.19.0 --namespace dapr-system --wait
Alternatively, you can use the latest version of CLI:
dapr init --runtime-version=1.19.0 -k
Post Installation
Check that the control plane pods are running and healthy:
$ dapr status -k
NAME NAMESPACE HEALTHY STATUS REPLICAS VERSION AGE CREATED
dapr-sidecar-injector dapr-system True Running 1 1.19.0 15s 2026-10-13 09:00.00
dapr-sentry dapr-system True Running 1 1.19.0 15s 2026-10-13 09:00.00
dapr-operator dapr-system True Running 1 1.19.0 15s 2026-10-13 09:00.00
dapr-placement-server dapr-system True Running 1 1.19.0 15s 2026-10-13 09:00.00
dapr-scheduler-server dapr-system True Running 3 1.19.0 15s 2026-10-13 09:00.00
After Dapr 1.19 has been installed, perform a rolling restart for your deployments to pick up the new version of the sidecar:
kubectl rollout restart deploy/<deployment-name>
Opt-in: Placement served by the Scheduler
The opt-in Helm value global.scheduler.placement.enabled (default false) makes the Scheduler service serve actor placement, instead of the standalone Placement service. Follow these steps.
- Prerequisites. Upgrade every sidecar to 1.19 or later first, and restart your applications after the control plane upgrade. If you use custom RBAC, make sure the Scheduler can get, list and watch
podsin the Dapr namespace. Keepglobal.scheduler.enabled,global.actors.enabledandglobal.actors.serviceName=placementas they are. The chart fails to render without them. - Enable. Run
helm upgradewith--set global.scheduler.placement.enabled=trueand your usual values. Pass the value on every laterhelm upgrade, because Helm resets values you do not pass. With the CLI,dapr upgrade -k --set global.scheduler.placement.enabled=truepasses the same value. The upgrade removes the Placement StatefulSet. The Schedulers detect this and take over within a few seconds — but the Schedulers also restart to pick up the new flag as part of this same upgrade, so expect actor and workflow activity to pause for longer than that while they come back up. No sidecar restarts are needed. Actors are re-placed once, and their state is kept. - Verify. Sidecars log
Connected to scheduler placement leader <address>. Exactly one Scheduler reportsdapr_scheduler_placement_leader= 1. Ifdapr_scheduler_placement_incapable_sidecarsis above 0, or a Scheduler logs "A sidecar running an older Dapr version is connected", upgrade those pods. Their actor and workflow APIs stall. - Roll back. Upgrade with the value set to
false. The Placement StatefulSet is redeployed, the Schedulers stop serving, and sidecars switch back to the Placement service without restarts. Actors are re-placed once more, and there is a short pause until the Placement pods are ready.
An older sidecar does not delay the switch. Once no Placement service remains, the Scheduler serves placement even if an older sidecar is still connected, and that sidecar's actor APIs stall until you upgrade its pod. It does not block placement for sidecars that have already upgraded. All Scheduler replicas must run with the same setting, which the chart ensures.
:::yaml
global:
scheduler:
placement:
enabled: true # default: false
Downgrading to Earlier Versions
[!warning] Do not roll back from 1.19 directly to 1.17.6 or earlier. The safe rollback target is 1.18.x.
Dapr 1.19 still issues the Ed25519 workload identity keys that Dapr 1.18 introduced (see the 1.18 release notes), and Sentry persists the Ed25519-keyed CA into the dapr-trust-bundle secret. Versions of Sentry before 1.17.7 cannot parse this bundle and will crash on startup with:
fatal: error creating CA: failed to get CA bundle:
failed to verify CA bundle: unsupported key type ed25519.PrivateKey
When Sentry is down, no new workload certificates can be issued. Existing sidecars with unexpired certificates keep working, but any sidecar restart or certificate expiry will fail to obtain a new identity. Dapr 1.19 does not change this floor from 1.18.
Compatibility matrix
| From | To | Result |
|---|---|---|
| 1.19 | 1.18.x | Safe. 1.18 and 1.19 write the same trust bundle format. |
| 1.19 | 1.17.7+ | Safe. 1.17.7 backports the Ed25519 PEM-decoder fix (#9904) so Sentry can read the trust bundle as-is. |
| 1.19 | 1.17.6 or earlier | Sentry crash-loops at startup. Do not attempt this rollback. |
| 1.17.6 or earlier | 1.19 | Safe. Sentry accepts CSRs of any algorithm, and existing ECDSA P-256 bundles are read transparently, as in 1.18. |
Safe rollback path
If you must downgrade below 1.17.7, go through 1.17.7 first:
- Roll the control plane back to 1.17.7. It includes the Ed25519 parsing fix and is the earliest version that can read a trust bundle written by 1.18 or 1.19.
- Allow Sentry to stabilise and confirm
dapr status -kis healthy. - From 1.17.7, downgrade to your target version. You may want to rotate the CA first to an algorithm the target version generates natively. See your Sentry CA rotation runbook.
Rolling back the control plane
Use Helm rollback (preferred) or re-install at the target version:
:::bash
# Helm: list revisions, then roll back to the desired one
helm history dapr -n dapr-system
helm rollback dapr <REVISION> -n dapr-system --wait
# Or pin a specific version
helm upgrade dapr dapr/dapr --version 1.18.7 --namespace dapr-system --wait
After the control plane is back, perform a rolling restart of your application Deployments so sidecars pick up the older injector image and re-issue their identities against the rolled-back Sentry.
If you turned on Placement served by the Scheduler
If you turned on global.scheduler.placement.enabled, turn it off before you downgrade. Keep this order:
- Set the value to
falsewithhelm upgradeand wait for the Placement pods to be ready. Sidecars then use the redeployed Placement service, with no restarts. - Verify that your sidecars reconnect to the Placement service. They log
Connected to placement <address>. - Downgrade the control plane.
- Downgrade the sidecars, with a rolling restart of your applications.
Turning the value off first is safe and sufficient. A 1.18 sidecar that starts while no Placement service is deployed has no placement, and its actor and workflow APIs stall. A helm rollback to a revision from before you turned the value on restores the Placement StatefulSet in the same operation.
If you created WorkflowAccessPolicy rules that use requires
A 1.18 control plane and sidecar do not know that field and apply those rules without the gate. Remove or narrow those rules before you downgrade.
What does NOT need to be rotated
Going 1.19 to 1.18.x or to 1.17.7 does not require manual CA rotation. The Ed25519-keyed bundle remains valid. 1.17.7 reads it, continues to issue new CSRs against the existing trust anchor, and ECDSA/RSA CSRs from 1.17.x sidecars are signed normally. Only re-rotate the CA if your downgrade target is below 1.17.7 or if your security posture requires it.
Breaking Changes
[!warning] Review carefully before upgrading
The changes below can require action when you upgrade from 1.18 to 1.19. The Dapr runtime API changes in 1.19 are additive. Most items here are behavior changes or SDK changes.
Dapr runtime and Kubernetes
- Helm upgrades: apply the 1.19 CRDs first.
helm upgradedoes not update CRDs. Until the 1.19WorkflowAccessPolicyCRD is applied, the API server drops the newrequiresfield, so a rule written withrequiresapplies without that gate. See Upgrading to Dapr 1.19. - Scheduler RBAC gets read access to pods in the Dapr namespace. The chart adds a
dapr-scheduler-podsRole and RoleBinding in the Dapr namespace that give the Schedulerget,listandwatchonpods. The Scheduler watches the Placement pods in its own namespace to detect whether a Placement service is deployed. It needs this whether or not you turn on Placement served by the Scheduler. Thedapr-schedulerClusterRole (or Role, in namespaced RBAC mode) keepsnamespacesonly. The Helm chart applies this on upgrade. If you manage RBAC outside the chart, or run policy checks against minimal RBAC scopes, account for the new Role. #10873 - Dapr Kubernetes Services set
appProtocol. Every port of every Service that Dapr creates now declaresappProtocol(http,grpc,tls,httpsortcp). A service mesh that selects proxy behavior from this field can now treat these ports differently. Ports that carry gRPC inside Dapr mTLS are declaredtls. #10232 - Workflow: no
outputfor a failed workflow. The workflow Get API no longer copies the failure message intodapr.workflow.outputfor a workflow in theFAILEDstate. Readdapr.workflow.failure.error_messageanddapr.workflow.failure.error_typeinstead. #10138 - Scheduler retries instead of exiting. When the Scheduler server stops with a runtime error, for example because its embedded store is briefly unavailable, the Scheduler now recreates it in the process. It uses a jittered backoff, from 500 ms up to 10 s. Meanwhile, its healthz endpoint reports not ready. For these errors, it no longer exits and restarts. Alerts that count Scheduler pod restarts no longer see this condition. Use readiness or the logs instead. A port that the Scheduler cannot bind is the exception, see the next entry. #10345
- Scheduler exits when it cannot bind its port. The retry in the previous entry does not apply to a bind failure. The Scheduler process exits, and Kubernetes restarts it, as in 1.18, so alerts that count Scheduler pod restarts still see this condition. The Scheduler port, 50006, is in the default Linux ephemeral port range, so one of the process's own outbound connections can hold it. daprd now binds its internal gRPC port (default 50002) once, before it connects to Sentry, the operator and the Schedulers, and keeps it across SIGHUP reloads. #10817, #10820
- Scheduler keeps 10,000 etcd revisions, not 1,000,000. The default retention drops from
1000000to10000, both for the flag--etcd-compaction-retentionand for the Helm valuedapr_scheduler.etcdCompactionRetention. The compaction mode staysrevision. Every revision of a deleted job keeps the job's payload until it is compacted, so the old default kept the payloads of the last million writes. After 15 hours of chaos testing, that was 2.7 GB of database and 3.4 GB of Scheduler memory, for 19 MB of live jobs. On the 1Gi volume that clusters installed before 1.17.7 keep, the database filled the disk and etcd writes failed. The database now holds at most 10,000 revisions plus 5 minutes of writes. The retention bounds the number of revisions, not their size. A value that you set yourself is not changed, andhelm upgrade --reuse-valueskeeps the old1000000, so pass the new value or drop the override. A Scheduler watch that falls more than 10,000 revisions behind, for example during a leadership change under a write burst, is cancelled by etcd. The Scheduler then re-reads the job list and reconnects, and job API calls wait until it is ready. #10818 - Metrics endpoints answer only GET and HEAD. The metrics server answered every HTTP method with 200 and the metrics text. It now answers POST, PUT, PATCH and DELETE with 405 and
Allow: GET, HEAD. Prometheus scrapes with GET, so scraping is unchanged. Update scripts or probes that call the endpoint with another method. #10669 - Actor timers: only the owning host accepts timer operations. A timer operation now fails on a sidecar that does not own the actor. The error is
ERR_ACTOR_TIMER_NOT_OWNED(HTTP 403, gRPCPermissionDenied). In 1.18 the same call succeeded and could leak a timer. This can surface during actor rebalancing. #10380 - Bounded actor reminder and timer span names. The reminder and timer HTTP endpoints, including the new list and get endpoints, now emit span names in the form
<API name>/<actorType>, for exampleRegisterActorReminder/OrderActororListActorTimers/OrderActor. The span name no longer contains the actor ID or the reminder or timer name. Update dashboards and alerts that match the old span names. #10141 --healthz-listen-addressand--metrics-listen-addressare honored. Placement, Scheduler, Sentry, the sidecar injector and the operator now bind their healthz server to the address in--healthz-listen-address, and Sentry, the injector and the operator bind their metrics server to the address in--metrics-listen-address. Before 1.19 the flags had no effect, and the servers always bound all interfaces. The defaults are unchanged. Set the flag to a specific address to avoid a conflict on the healthz port with another process or interface. #10394, #10783- Workflow: a clear error when no workflow worker is connected. Workflow actor types exist only while an app worker holds its work-item stream open. Without a connected worker, workflow operations now fail with
no workflow worker is connected for app '<app-id>'instead of actor routing errors such asdid not find address for actor. This covers start, raise event, terminate, pause, resume, purge, rerun and the wait operations, local and cross-app. Starting a workflow no longer retries in that case, so the error comes about 20 seconds sooner. The original error stays wrapped, so existing error codes still match. #10865 - Pub/sub: deliveries without trace context start a root span. When a message carries no W3C trace context (no
traceparentand no legacytraceid), the sidecar now starts a new root span for the delivery, and the app receives atraceparentheader. Before 1.19 such deliveries had no span and an emptytraceparent, so a message published outside Dapr, or re-queued from a dead letter topic, was invisible in traces. Expect new traces for these messages. Nothing changes when tracing is off in the Configuration. #10511
Components
- Redis pub/sub:
redeliverIntervalis honored. A duration string such as"30s"was ignored, and the component always used 15 seconds. The configured value now applies. Components that do not set this field are not affected. components-contrib#4601 - Solace AMQP pub/sub: a handler error redelivers the message.
pubsub.solace.amqpnow answers a handler error with the AMQPmodifiedoutcome, so the broker delivers the message again. Before 1.19 it answeredrejected, and the broker dead-lettered the message. TLS settings (caCert,clientCert,clientKey) on a plainamqp://URL are now rejected when the component initializes. Before, the component ignored them and connected without TLS. components-contrib#4602 - Azure App Configuration:
retryDelayis honored. The setting now controls the initial retry delay as documented. Before 1.19 the component usedmaxRetryDelayinstead, so expect faster first retries. components-contrib#4461 - Anthropic conversation: new default model. The default model is now
claude-sonnet-4-6, because the previous default model is retired. To keep a specific model, setmodelin the component metadata. components-contrib#4532
Python SDK
- Extension packages are no longer published separately. Remove these packages from your project:
dapr-ext-fastapi,dapr-ext-grpc,dapr-ext-langgraph,dapr-ext-strands,dapr-ext-workflowandflask-dapr. Then install the matching extras of the core package, for examplepip install "dapr[fastapi,workflow]". Uninstall the old packages before you reinstalldapr. python-sdk#1054 - Higher minimum
protobufandgrpcioversions. The SDK needsprotobuf6.33.5 or later andgrpcioandgrpcio-status1.81.1 or later. python-sdk#1126 when_allwaits for every task. A failingwhen_allnow reports the first failure only after all tasks finish. python-sdk#1166- Streaming subscriptions no longer return
Noneafter a reconnect. After a transient stream error,next_message()and iteration reconnect and return the next message. After five failed reconnects in one call they raiseStreamReconnectError. A stream that the server ends cleanly now also reconnects instead of raising an error, and the async client also retriesINTERNALerrors. If your code treatedNoneas a reconnect signal, handleStreamReconnectErrorinstead. python-sdk#1231 - Workflow worker readiness reflects the connection.
is_worker_ready()andwait_for_worker_ready()now report not ready while the worker's work-item stream to the sidecar is down. Before 1.19 they stayed true after the first connection. Readiness probes built on these methods can now report not ready during a reconnect. python-sdk#1312 - Actor
get_state_namesduring a transaction. The method now excludes only keys marked for removal. Earlier releases also returned removed keys and skipped updated ones. python-sdk#1208 - Bulk publish metadata reaches plain entries.
publish_metadataonpublish_eventsnow applies to entries that do not carry their own metadata. Before 1.19 it was dropped for those entries. python-sdk#1228 DAPR_API_TIMEOUT_SECONDSno longer limits workflow waits.wait_for_workflow_startandwait_for_workflow_completionignore this setting. Without their owntimeout_in_seconds, they wait with no time limit. If you relied on the global setting, passtimeout_in_seconds. python-sdk#1244- Conversation tool calls:
Noneis rejected for required parameters. When the SDK runs a tool function for a Conversation API tool call,Nonefor a required (non-Optional) parameter was turned into the string'None', or passed through and failed later with an unclear error. It now raisesToolArgumentError. Handle this error where you run tool calls. python-sdk#1225 - Sub-second durations are serialized correctly.
dapr.serializers.util.convert_to_dapr_durationrounded a sub-second part of 0.5 seconds or more up into an extra second, sotimedelta(milliseconds=1500)was sent as 2.5 seconds. It now sends 1.5 seconds. Actor reminders and timers with sub-second due times or periods now fire at the intended times. python-sdk#1192 - Empty duration strings are rejected.
dapr.serializers.util.convert_from_dapr_durationparsed an empty string, or a string with no duration part, to a zerotimedelta. It now raisesValueError. The actor gRPC client uses this helper for theintervalof a retry policy, for example. python-sdk#1221 - Relative unix socket endpoints fail fast. A
unix://endpoint with an authority, such asunix://dapr.sock, now raisesValueErrorwhen the client is created. Before 1.19 it waited until the connection timed out. gRPC needs an absolute path, as inunix:///tmp/dapr.sock. python-sdk#1226
Java SDK
- Spring integration requires Spring Boot 4.0. Move to Spring Boot 4.0 before you take SDK 1.19. Or stay on SDK 1.18.x with Spring Boot 3.5. The two combinations are not binary compatible and fail at runtime. java-sdk#1772
- Separate Spring Boot 4 artifacts are removed. Replace
dapr-spring-boot-4-starter,dapr-spring-boot-4-starter-testanddapr-spring-boot-4-autoconfigurewith the artifacts without-4in the name. Replacedapr-spring-6-datawithdapr-spring-data, and change imports fromio.dapr.spring6.datatoio.dapr.spring.data. java-sdk#1772 WorkflowInstanceAlreadyExistsException.scheduleNewWorkflowthrows this exception for a duplicate active instance ID instead of a rawStatusRuntimeException. java-sdk#1782- Netty 4.2. The SDK now pulls Netty 4.2.x. A project that pins Netty 4.1.x directly can get a dependency conflict. java-sdk#1814
Workflow history cache in the Python, Java, .NET and Go SDKs
Workflow workers built with the 1.19 Python, Java or .NET SDK, or with Go SDK 1.16 (durabletask-go v0.15.0 or later), keep each workflow's history in memory between turns. This cache is on by default. If worker memory is limited, disable it with disable_stateful_history (Python), withStatefulHistoryDisabled (Java) or DisableStatefulHistory (.NET). The Go SDK has no switch; build the durabletask-go client with client.WithStatefulHistoryDisabled(). python-sdk#1112, java-sdk#1777, dotnet-sdk#1862
JavaScript SDK
- New workflow engine. The SDK replaced its workflow engine and wire-protocol handling.
WorkflowContext,DaprWorkflowClientandWorkflowStatekeep their public method names, but re-test workflow code after you upgrade. js-sdk#857 grpcOptionsonDaprWorkflowClient. Only message-size options still take effect. Keepalive, credential, compression and other grpc-js settings are ignored without an error. js-sdk#857
Dapr CLI
- Workflow activity job names end in
::0. On a 1.19 runtime,dapr scheduler list,getanddeleteshow workflow activity jobs asactivity/<app-id>/<instance-id>::<task-id>::0. Earlier runtimes used the instance's generation in the last component, for example::1on the first run. Update scripts that build these names. [#10283], [#10504]
Changes that also shipped in 1.18 patch releases
These changes also shipped in 1.18 patch releases, and each entry names the release. If you upgrade from that 1.18 release or a later one, the change is not new for you.
- Service invocation: caller identity headers come from the sidecar. With mTLS on, the target app gets
dapr-caller-app-idanddapr-caller-namespaceonly from its own sidecar. The sidecar sets them from the caller's mTLS identity, and it removes any value that the calling app sets. Calls through the gRPC proxy now also carrydapr-caller-namespace. The same change is in 1.18.6. #10683 - Service invocation: some encoded methods fail. A method with
%2F,%5C,%2E(any letter case) or a literal\now fails before the access control check. This covers the HTTP and gRPC APIs, calls between sidecars, proxied gRPC calls and actor method invocation. The same change is in 1.18.6. #10684 - Actor invoke API rejects reserved actor types. gRPC
InvokeActorand HTTP/v1.0/actors/{type}/{id}/method/{method}now reject everydapr.internal.*actor type. The error isERR_ACTOR_TYPE_RESERVED(gRPCPermissionDenied, HTTP 403). The actor state, reminder and timer APIs already did this. The same change is in 1.18.6. #10685 - Operator: a sidecar gets only the configuration that its pod names.
GetConfigurationnow returns only the configuration named in thedapr.io/configannotation of one of the calling app's pods. Otherwise it returnsPermissionDenied. This affects a daprd that you run in Kubernetes mode without the injector, with--config. Its pod must have thedapr.io/enabled: "true",dapr.io/app-idanddapr.io/configannotations and thedapr.io/app-idlabel. Its container must be nameddaprd, so that the injector does not add a second one. Otherwise the Operator refuses the configuration, and daprd fails to start. The Operator also stops sending a sidecar the HTTP endpoints, MCP servers, resiliencies, subscriptions and workflow access policies that are not scoped to its app. Sidecars already ignored those resources, so apps see no change. The same changes are in 1.18.9 and 1.17.18. #10890 - Jobs and reminders: a timezone with
@everyis rejected. A schedule such asCRON_TZ=Europe/Rome @every 1hnow fails at parse time withtimezone is not supported for @every schedules. Before, the timezone was silently ignored, because an@everyschedule fires at a fixed interval and has no wall clock. Remove the prefix from@everyschedules. Cron expressions with a timezone keep working. The same change is in 1.18.3. kit#161 - Azure Event Hubs pub/sub and input binding: checkpoints move only past successfully handled events. Before, the checkpoint could move past a failed batch. Now the component retries a failed batch with the
backOff*settings until the handler succeeds.backOffMaxRetriesno longer stops the retries, so an event that always fails holds the checkpoint of its partition. In the concurrent mode (enableInOrderMessageDelivery: false), the newmaxConcurrentHandlersoption (default100) limits the batches per partition that wait for a checkpoint. At that limit, the component pauses receives for the partition. A consumer group with no stored checkpoint now starts from the earliest retained event, not the latest. The same change is in 1.18.5 (components-contrib#4606). components-contrib#4598 - Pub/sub: inbound retries stop when the component cancels the handler. Inbound retries now use the handler's own context. Before 1.19, they used a context that never ended. A Kafka rebalance, for example, now stops the retries and the in-flight app call. The consumer that takes the partition then gets the message again. Azure Service Bus (
handlerTimeoutInSec, default 60 s) and Redis Streams (processingTimeout, default 60 s) put a timeout on the handler. That timeout now also limits these retries. A message that exceeds it goes to the dead-letter topic, as on the bulk path. The same change is in 1.18.5. #10497 - .NET SDK:
DaprWorkflowClient.GetWorkflowStateAsyncrethrows errors other than NotFound. Before SDK 1.18.5, any gRPC error from the runtime was swallowed into aWorkflowStatewithExistsset tofalse, so a transient error such asUnavailablelooked like a workflow that does not exist. Now only aNotFoundstatus givesExists == false. Every other gRPC failure reaches your code as anRpcException. HandleRpcExceptionwhere you poll workflow state. The same change is in 1.18.5. dotnet-sdk#1877
Deprecation Notices
- Standalone Placement service. Starting with 1.19, the Scheduler can serve actor placement, enabled with
global.scheduler.placement.enabled=true(falseby default). The standalone Placement service remains the default in 1.19. The proposal is to make Scheduler-served placement the default in a later release, and to deprecate the standalone Placement service two releases after that. No removal date is set. No action is required in 1.19. See the Placement service docs and breaking changes and deprecations. - Python SDK: CloudEvents handler type in
dapr.ext.grpc. Annotate the event parameter of topic handlers withdapr.ext.grpc.SubscriptionMessage, the same type that streaming subscriptions deliver. Handlers that are unannotated, or annotated withcloudevents.sdk.event.v1.Event, receive the CloudEvents-based event, andsubscribe()emits aDeprecationWarningwhen it registers them. The timeline: - In 1.20, unannotated handlers receive
SubscriptionMessage. The CloudEvents type is delivered only to handlers annotated with it. - In 1.21,
cloudeventsis no longer installed by thedapr[grpc]extra. - In 1.22, the CloudEvents-based type is removed.
- Python SDK:
flask_daprimport path and legacy extension installs. The top-levelflask_daprpackage is now a shim that emits aFutureWarning. Import fromdapr.ext.flaskinstead.import dapralso emits aFutureWarning, with the command to fix it, when it finds an olddapr-ext-*orflask-daprpackage installed. Both warnings and theflask_daprshim remain through 1.21 and are removed in 1.22. See Breaking Changes. python-sdk#1054 - Python SDK:
reuse_id_policyonschedule_new_workflow. Deprecated since 1.18.3. The parameter has no effect and emits aDeprecationWarning: an instance ID can always be reused once the existing instance is in a terminal state. Remove the argument. It is planned for removal in 1.21. python-sdk#1145 - Python SDK:
http://andhttps://prefixes on the gRPC endpoint. A gRPC endpoint with a legacy scheme, for examplehttps://grpc.example.com:443inDAPR_GRPC_ENDPOINT, now emits aDeprecationWarningthat names the equivalent form, heregrpc.example.com:443?tls=true. Usehost:port?tls=trueorhost:port?tls=falseinstead. Before 1.19 the SDK emitted aUserWarning, so a warnings filter onUserWarningno longer matches. Python hides aDeprecationWarningin many cases, so run with-W defaultto see it. Endpoint parsing and TLS behavior are unchanged, and the endpoints keep working. No removal date is set. python-sdk#1276 - .NET SDK:
Dapr.Actorsis in maintenance mode.Dapr.Actorsnow receives security fixes only, and new actor development happens inDapr.Actors.Next.Dapr.Actorsis not deprecated: existing code keeps working, and no deprecation or removal date is set. - .NET SDK: .NET 8 and .NET 9 target frameworks. Be advised that the .NET 8 and .NET 9 frameworks will fall out of support in November 2026. As such, both will be dropped from the next v1.20 release.