Actors (Next)

Dapr.Actors.Next is a reimplementation of the Dapr Actors building block for .NET. The original Dapr.Actors package has been in service for a long time and predates much of what the modern Dapr .NET SDK now relies on, so this package updates the actor experience to match: it talks to the runtime over the bidirectional gRPC streaming introduced in Dapr 1.18, removes reflection from the actor path, and brings actors in line with the dependency injection, options, serialization, and source generator patterns used elsewhere in the SDK.

The actor model itself is unchanged. Actors are still virtual, addressed by type and id, with reentrancy, timers, reminders, and proxying. Dapr.Actors.Next is a separate package family and is not API-compatible with Dapr.Actors, but it is fully wire-compatible with the Dapr runtime, so adopting it requires no runtime changes except that this will only work with the Dapr runtime v1.18 or later.

What changed

This rewrite was born out of the two core ideas:

  1. The first is how the SDK interfaces with the runtime. Actor callbacks (invoke, reminder, timer, and deactivate) now arrive over a long-lived bidirectional gRPC stream rather than per-call requests into a hosted actor endpoint, which lowers per-call overhead and removes the need to map inbound actor handlers. This is the same streaming pattern Dapr already uses for pub/sub subscriptions and workflow dispatch.
  2. The second is the amount of work the SDK now does locally, on your side of that connection (both at build and runtime), to make actor code easier and safer to write. Source generators replace the reflection-based proxy and dispatch machinery, which both removes a runtime cost and enables Native AOT. Serialization moves to the same pluggable IDaprSerializer used by State management and Workflows. State migration, a state machine programming model, pub/sub-driven actors, and a deterministic in-memory test runtime are all provided in the box. The result is meant to make it straightforward to build high-performance actor applications using the rest of the modern Dapr .NET SDK rather than a separate set of actor-specific conventions.

Source generators and compile-time checks

Source generators do most of the wiring that you used to write or that the old SDK did with reflection. From your actor interface and implementation, the generator produces the client proxy, the server-side dispatcher, the activation factory, the registration, and an actor registry describing every actor and its method signatures. None of this is hand-written, and none of it runs through reflection at call time, which is what keeps the path AOT-friendly.

Alongside the generators, the package ships analyzers and code fixes that catch actor-specific mistakes while you type: methods that aren’t serializable or don’t return a task type, blocking calls or thread escapes inside a turn, time read from the clock instead of an injected TimeProvider, a state change that would break deserialization of existing data, or a gap in a state migration chain. Where a fix is mechanical, the analyzer offers one. The full set is listed in the diagnostics reference.

How it differs from Dapr.Actors

ConcernDapr.Actors (original)Dapr.Actors.Next
Runtime connectivityInbound actor-handler endpoints the runtime calls into per invocationActor callbacks over an outbound persistent SubscribeActorEvents stream; no actor endpoints to map (the app’s gRPC server port remains)
Proxies and dispatchReflection (DispatchProxy, runtime IL)Source-generated; no reflection on the hot path
Native AOT and trimmingNot supportedSupported; runtime packages are trim/AOT clean
Nullable reference typesPartialEnabled across the public surface
RegistrationManual RegisterActor<T>() per typeSource-generated discovery; actors are not registered by hand
Hosting setupapp.MapActorsHandlers() endpoint mappingAddDaprActors() only; the host dials the runtime
Dependency injectionBespokePer-activation DI scope; constructor injection of registered services
Proxy flavorsRemoting proxy (.NET-to-.NET) and non-remoting proxy (cross-app)One proxy; no remoting/non-remoting distinction
SerializationDataContract via the remoting proxy, or System.Text.Json via the non-remoting proxyPluggable IDaprSerializer (default System.Text.Json) for every call; no DataContract built in
ConfigurationBespokeOptions pattern (IOptions<DaprActorsOptions>)
TestingIntegration tests against a sidecarIn-memory deterministic runtime plus optional Coyote deep testing
State versioningManualState-envelope schema versioning with upcaster chains
State machinesNot providedFirst-class StateMachineActor<TState, TData> model
Pub/sub integrationNot providedBuilt-in [Subscribe] subscription streams
Per-actor state cacheYesYes (retained)

Nullability and modernization

The public surface is annotated for nullable reference types, so the compiler distinguishes an actor method that may return no value from one that always returns a result, and flags the difference at build time rather than at call time. Combined with source-generated proxies and serialization, this removes a category of error the reflection-based SDK could only surface at runtime.

The modernization is functional rather than cosmetic. Removing reflection is what makes Native AOT possible and lowers startup and memory cost. The options pattern replaces bespoke configuration. A real per-activation DI scope means an actor’s dependencies are resolved and disposed on the same lifecycle as the actor. A single pluggable serializer means actors, state management, and workflows serialize the same way.

Core concepts

Each concept has its own page:

  • Author, register, and call actors: attributes, what the source generator produces, the minimum you must register, and cross-assembly and cross-app scenarios.
  • Serialization: the pluggable serializer, and the per-actor cache.
  • State migration: The state envelope and versioning state with upcasters.
  • State machine actors: the StateMachineActor model, when to choose it over a workflow, and how to test it.
  • Subscription streams: driving actors from pub/sub topics with [Subscribe].
  • Dynamic invocation: calling actors by type, id, and method with no compile-time contract, for gateways, tooling, and cross-language callers.
  • Testing: the in-memory test runtime, xUnit usage, and optional Coyote integration for deep concurrency testing.

Learn by example

If you would rather see the improvements one at a time with runnable code, the tutorial walks through six worked examples, each paired with its test, with the code in the solution under /examples/Actor.Next/. It is the fastest way to understand what changed and why.

Next steps


Migrating from Dapr.Actors to Dapr.Actors.Next

A concept-by-concept guide for moving an existing Dapr.Actors (and Dapr.Actors.AspNetCore) actor layer to Dapr.Actors.Next

How to: Author, register, and call actors with the .NET SDK

Define actors, let the source generator wire them up, and call them with Dapr.Actors.Next

Serialization in the .NET SDK

Pluggable serialization, modern C# type support, and the per-actor state cache

State migration in the .NET SDK

Evolve actor state safely across releases with upcaster chains, additive auto-generation, and a graduation offramp

State machine actors in the .NET SDK

Author long-lived reactive entities as state machines with StateMachineActor, and test them deterministically

Subscription streams in the .NET SDK

Drive actors from pub/sub topics with [Subscribe] using Dapr.Actors.Next

Dynamic actor invocation in the .NET SDK

Call actors by type, id, and method with no compile-time contract, for gateways, tooling, and cross-language callers

Testing actors in the .NET SDK

Deterministically test actor concurrency, timers, reminders, and failures with the in-memory runtime, xUnit v3, and Coyote

Tutorial: Dapr.Actors.Next by example

A six-part, example-driven tour of what changed in the modernized Dapr Actors implementation, with the testing for each

Last modified July 13, 2026: Fix baseUrl for current (#5242) (d29da20)