Nexus .NET Quickstart
Temporal Nexus connects Temporal Applications within and across Namespaces using a Nexus Endpoint, a Nexus Service contract, and Nexus Operations. Build a Nexus Service that wraps an existing Temporal Workflow, then invoke it from a caller Workflow.
This page will help you get a working sample running in .NET.
To evaluate whether Nexus fits your use case, see the evaluation guide and to learn more about Nexus features, click here.
Prerequisites: Complete the .NET SDK Quickstart first.
You should have SayHelloWorkflow, MyActivities, and a Worker project from that guide.
What you'll build
You have SayHelloWorkflow running in the default Namespace.
By the end of this guide:
- A Nexus Service will expose
SayHelloWorkflowas an Operation. - A second Namespace will contain a Workflow that calls that Operation.
- The caller Workflow will get back
"Hello, Temporal!"— the same result, but across Namespaces.
1. Define the Nexus Service
Create a file called ISayHelloNexusService.cs in the Workflow project.
The [NexusService] attribute on an interface defines the Nexus Service contract. [NexusOperation] marks each method that callers can invoke. The EndpointName static field is shared between the handler and caller to keep the endpoint name in one place.
SayHelloWorkflow returns string, so the operation output type is string. The input is a record carrying the workflow argument.
namespace MyNamespace;
using NexusRpc;
[NexusService]
public interface ISayHelloNexusService
{
public static readonly string EndpointName = "my-nexus-endpoint-name";
[NexusOperation]
string SayHello(MyInput input);
public record MyInput(string Name);
}
2. Define the Nexus Operation handlers
Create a file called SayHelloNexusServiceHandler.cs in the Workflow project.
[NexusServiceHandler] links this class to the ISayHelloNexusService contract. Each [NexusOperationHandler] method returns an IOperationHandler that describes how the operation runs.
WorkflowRunOperationHandler.FromHandleFactory creates an asynchronous operation backed by a Workflow run. The input.Name bridges the Nexus MyInput record to SayHelloWorkflow's string parameter.
Using context.HandlerContext.RequestId as the Workflow ID ensures that retried Nexus operation requests are deduplicated.
namespace MyNamespace;
using NexusRpc.Handlers;
using Temporalio.Nexus;
[NexusServiceHandler(typeof(ISayHelloNexusService))]
public class SayHelloNexusServiceHandler
{
[NexusOperationHandler]
public IOperationHandler<ISayHelloNexusService.MyInput, string> SayHello() =>
WorkflowRunOperationHandler.FromHandleFactory(
(WorkflowRunOperationContext context, ISayHelloNexusService.MyInput input) =>
context.StartWorkflowAsync(
(SayHelloWorkflow wf) => wf.RunAsync(input.Name),
new() { Id = context.HandlerContext.RequestId }));
}
3. Register the Nexus Service handler in a Worker
Update Worker/Program.cs to register the Nexus Service handler alongside the existing Workflow and Activity registrations.
A Worker will only handle incoming Nexus requests if the Nexus Service handlers are registered. Like .AddActivity(), .AddNexusService() takes an instance — both register concrete objects that the Worker dispatches work to.
// Worker/Program.cs
var activities = new MyActivities();
using var worker = new TemporalWorker(
client,
new TemporalWorkerOptions("my-task-queue")
.AddActivity(activities.SayHello)
.AddWorkflow<SayHelloWorkflow>()
.AddNexusService(new SayHelloNexusServiceHandler()));
4. Develop the caller Workflow
Create a file called CallerWorkflow.cs in the Workflow project.
The caller Workflow uses Workflow.CreateNexusWorkflowClient<T>() to get a typed client bound to the Nexus Endpoint. ExecuteNexusOperationAsync starts the operation and waits for the result.
The caller only depends on the Service contract (ISayHelloNexusService), not the handler implementation. This decoupling is what allows the caller and handler to live in separate Namespaces or even separate codebases.
namespace MyNamespace;
using Temporalio.Workflows;
[Workflow]
public class CallerWorkflow
{
public static readonly string CallerTaskQueue = "my-caller-task-queue";
[WorkflowRun]
public async Task<string> RunAsync(string name)
{
return await Workflow
.CreateNexusWorkflowClient<ISayHelloNexusService>(
ISayHelloNexusService.EndpointName)
.ExecuteNexusOperationAsync(svc => svc.SayHello(new(name)));
}
}
5. Create the caller Namespace and Nexus Endpoint
Before running the application, create a caller Namespace and a Nexus Endpoint to route requests from the caller to the handler. The handler uses the default Namespace that was created when you started the dev server.
Namespaces provide isolation between the caller and handler sides. The Nexus Endpoint acts as a routing layer that connects the caller Namespace to the handler's target Namespace and Task Queue. The endpoint name must match the EndpointName constant defined in Step 1.
Make sure your local Temporal dev server is running (temporal server start-dev).
temporal operator namespace create --namespace my-caller-namespace
temporal operator nexus endpoint create \
--name my-nexus-endpoint-name \
--target-namespace default \
--target-task-queue my-task-queue
6. Run and Verify
Create a CallerStarter console project that starts a caller Worker and executes the Workflow.
Add the CallerStarter project:
dotnet new console -o CallerStarter
dotnet sln TemporalioHelloWorld.sln add CallerStarter/CallerStarter.csproj
dotnet add CallerStarter/CallerStarter.csproj reference Workflow/Workflow.csproj
dotnet add CallerStarter/CallerStarter.csproj package Temporalio
This step brings everything together: the caller Worker hosts CallerWorkflow, which uses the Nexus client to invoke SayHello on the handler side. The full request flows from the caller Workflow, through the Nexus Endpoint, to the handler Worker running SayHelloWorkflow, and back to the caller.
Run the application:
- Start the handler Worker in one terminal:
dotnet run --project Worker/Worker.csproj
- Run the caller in another terminal:
dotnet run --project CallerStarter/CallerStarter.csproj
You should see:
Workflow result: Hello, Temporal!
Open the Temporal Web UI and find the CallerWorkflow execution in the my-caller-namespace Namespace. You should see NexusOperationScheduled, NexusOperationStarted, and NexusOperationCompleted events in the Workflow history.
// CallerStarter/Program.cs
using MyNamespace;
using Temporalio.Client;
using Temporalio.Worker;
var client = await TemporalClient.ConnectAsync(
new("localhost:7233") { Namespace = "my-caller-namespace" });
using var tokenSource = new CancellationTokenSource();
Console.CancelKeyPress += (_, eventArgs) =>
{
tokenSource.Cancel();
eventArgs.Cancel = true;
};
using var worker = new TemporalWorker(
client,
new TemporalWorkerOptions(CallerWorkflow.CallerTaskQueue)
.AddWorkflow<CallerWorkflow>());
Console.WriteLine("Running caller worker");
var workerTask = worker.ExecuteAsync(tokenSource.Token);
var result = await client.ExecuteWorkflowAsync(
(CallerWorkflow wf) => wf.RunAsync("Temporal"),
new(id: $"caller-workflow-{Guid.NewGuid()}",
taskQueue: CallerWorkflow.CallerTaskQueue));
Console.WriteLine("Workflow result: {0}", result);
tokenSource.Cancel();
try { await workerTask; } catch (OperationCanceledException) { }
Next Steps
Now that you have a working Nexus Service, here are some resources to deepen your understanding:
- .NET Nexus Feature Guide: Covers synchronous and asynchronous Operations, error handling, cancellation, and cross-Namespace calls.
- Nexus Operations: The full Operation lifecycle, including retries, timeouts, and execution semantics.
- Nexus Services: Designing Service contracts and registering multiple Services per Worker.
- Nexus Patterns: Comparing the collocated and router-queue deployment patterns.
- Error Handling in Nexus: Handling retryable and non-retryable errors across caller and handler boundaries.
- Execution Debugging: Bi-directional linking and OpenTelemetry tracing for debugging Nexus calls.
- Nexus Endpoints: Managing Endpoints and understanding how they route requests.
- Temporal Nexus on Temporal Cloud: Deploying Nexus in a production Temporal Cloud environment with built-in access controls and multi-region connectivity.