Example caller Workflow invoking Nexus operation in C#
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)));
}
}
This example shows a Workflow that creates a Nexus client and invokes the SayHello operation.
Connect TemporalClient to specific Namespace
When creating a TemporalClient, specify the target Namespace using the TemporalConnectionOptions constructor: new("localhost:7233") { Namespace = "my-caller-namespace" }. This allows the client to connect to a specific Namespace rather than the default one.
Example caller starter program setup
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) { }
This example shows how to set up a caller Worker, start it, execute a caller Workflow, and handle cancellation.
Nexus Service definition with [NexusService] attribute
Define a Nexus Service by creating an interface decorated with the [NexusService] attribute. Mark each callable method with [NexusOperation]. Include a static EndpointName field to keep the endpoint name in one place for use by both handler and caller. The operation output type matches the method return type, and input is typically a record carrying the workflow arguments.
Example Nexus Service interface definition in C#
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);
}
This example defines a Nexus Service with one operation that takes a MyInput record and returns a string.
Nexus Operation handler definition with [NexusServiceHandler]
Create a Nexus Operation handler class decorated with [NexusServiceHandler(typeof(TService))] where TService is the service interface. Mark each handler method with [NexusOperationHandler]. Use WorkflowRunOperationHandler.FromHandleFactory to create asynchronous operations backed by Workflow runs. Use context.HandlerContext.RequestId as the Workflow ID to ensure retried Nexus operation requests are deduplicated.
Example Nexus Operation handler in C#
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 }));
}
This example shows how to handle a Nexus operation by starting a Workflow run and using the request ID as the Workflow ID for deduplication.
Example registering Nexus Service handler in Worker
var activities = new MyActivities();
using var worker = new TemporalWorker(
client,
new TemporalWorkerOptions("my-task-queue")
.AddActivity(activities.SayHello)
.AddWorkflow<SayHelloWorkflow>()
.AddNexusService(new SayHelloNexusServiceHandler()));
This example shows how to register a Nexus Service handler alongside Activity and Workflow registrations in a Worker.
Standalone Nexus Operations .NET SDK version requirement
Standalone Nexus Operations require .NET SDK version 1.16.0 or above. All APIs are experimental and may be subject to backwards-incompatible changes.
Count Standalone Nexus Operations
Use ITemporalClient.CountNexusOperationsAsync() to count Standalone Nexus Operation Executions that match a List Filter query. CountNexusOperationsAsync is called on the base ITemporalClient, not on the NexusClient.
List Nexus Operations example
Example of listing Standalone Nexus Operations:
await foreach (var execution in client.ListNexusOperationsAsync(
"Endpoint = 'my-nexus-endpoint'"))
{
logger.LogInformation(
"OperationID: {Id}, Operation: {Operation}, Status: {Status}",
execution.OperationId, execution.Operation, execution.Status);
}
List Standalone Nexus Operations
Use ITemporalClient.ListNexusOperationsAsync() to list Standalone Nexus Operation Executions that match a List Filter query. The call returns an IAsyncEnumerable<NexusOperationExecution> that you can iterate with await foreach. ListNexusOperationsAsync is called on the base ITemporalClient, not on the NexusClient.
Recover handle for already-started Nexus Operation
You can recover a handle for an already-started Nexus Operation using GetNexusOperationHandle<TResult>() on the Temporal Client:
var handle = client.GetNexusOperationHandle<IHelloService.EchoOutput>("unique-operation-id");
var output = await handle.GetResultAsync();
Execute Standalone Nexus Operation with untyped client
Example of executing a Standalone Nexus Operation with an untyped NexusClient using operation name as a string:
var nexusClient = client.CreateNexusClient("my-nexus-endpoint", "HelloService");
var handle = await nexusClient.StartNexusOperationAsync<IHelloService.EchoOutput>(
"Echo",
new IHelloService.EchoInput("Nexus Echo 👋"),
new("unique-operation-id")
{
ScheduleToCloseTimeout = TimeSpan.FromSeconds(10),
});
Execute Standalone Nexus Operation with typed client
Example of executing a Standalone Nexus Operation with a typed NexusClient:
var nexusClient = client.CreateNexusClient<IHelloService>("my-nexus-endpoint");
var result = await nexusClient.ExecuteNexusOperationAsync(
svc => svc.Echo(new("Nexus Echo 👋")),
new("unique-operation-id")
{
ScheduleToCloseTimeout = TimeSpan.FromSeconds(10),
});
NexusOperationOptions requirements and defaults
On NexusOperationOptions, the Id field is required. ScheduleToCloseTimeout is optional and defaults to the maximum allowed by the Temporal server.
Count Nexus Operations example
Example of counting Standalone Nexus Operations:
var count = await client.CountNexusOperationsAsync(
"Endpoint = 'my-nexus-endpoint'");
logger.LogInformation("Total Nexus operations: {Count}", count.Count);
ExecuteNexusOperationAsync shortcut method
ExecuteNexusOperationAsync is a shortcut that starts a Standalone Nexus Operation and waits for the result. If you need a handle to the Operation while it runs, call StartNexusOperationAsync instead, which returns a NexusOperationHandle.
Context propagation over Nexus uses interceptors, not ContextPropagator
Nexus does not use the ContextPropagator interface. It relies on a Temporal-agnostic protocol with its own header format (nexus.Header, a wrapper around map[string]string). To propagate context over Nexus Operation calls, use interceptors to explicitly serialize and deserialize context into the Nexus header.
Temporal Nexus documentation structure for Go SDK
The Temporal Nexus documentation for the Go SDK is organized into three main sections: Quickstart, Feature guide, and Standalone Operations.
Nexus Service decouples caller and handler implementations
Nexus Services provide loose coupling between caller and handler implementations. The caller depends only on the Service contract (constants and input/output types), not the handler implementation. This allows caller and handler to live in separate Namespaces, repositories, or even teams while remaining type-safe through the shared contract definition.
Standalone Nexus Operations require Go SDK v1.46.0 or above
Standalone Nexus Operations require Go SDK version 1.46.0 or above. All APIs are experimental and may be subject to backwards-incompatible changes.
Java SDK Nexus documentation sections
Temporal Nexus documentation for Java includes: Quickstart, Feature guide, and Standalone Operations.
Java SDK Nexus documentation structure
The Java SDK Nexus documentation is organized into four main sections: Quickstart, Feature guide, Standalone Operations, and a Nexus sync tutorial available at learn.temporal.io.
Temporal Nexus Java SDK overview
Temporal Nexus allows connecting Temporal Applications within and across Namespaces using a Nexus Endpoint, a Nexus Service contract, and Nexus Operations. The Nexus Java SDK is used to develop Nexus Services, Operation handlers, and caller Workflows that use Nexus Services.
Get Standalone Nexus Operation result via CLI
Wait for a Standalone Nexus Operation result by Operation ID using the Temporal CLI: ./temporal nexus operation result --namespace my-caller-namespace --operation-id my-greet-op
Count Standalone Nexus Operations with GROUP BY
Passing a GROUP BY query to countNexusOperationExecutions() (for example, "GROUP BY ExecutionStatus") returns a count per group, available through NexusOperationExecutionCount.getGroups().
Count Standalone Nexus Operations example
String query = "Endpoint = \"" + ENDPOINT_NAME + "\"";
NexusOperationExecutionCount count = nexusClient.countNexusOperationExecutions(query);
System.out.println("Total Nexus operations: " + count.getCount());
List Filter syntax for Standalone Nexus Operations
The query parameter for listNexusOperationExecutions() accepts List Filter syntax. For example: "Endpoint = 'my-endpoint' AND ExecutionStatus = 'Running'"
List Standalone Nexus Operations example
String query = "Endpoint = \"" + ENDPOINT_NAME + "\"";
nexusClient
.listNexusOperationExecutions(query)
.forEach(
op ->
System.out.printf(
"OperationId: %s, Operation: %s, Status: %s%n",
op.getOperationId(), op.getOperation(), op.getStatus()));
ExecuteAsync Standalone Nexus Operation example
CompletableFuture<GreetingOutput> future =
greetingClient.executeAsync(
GreetingNexusService::greet, options, new GreetingInput("World"));
GreetingOutput greeting = future.get();
Execute Standalone Nexus Operation via CLI
Execute a Standalone Nexus Operation using the Temporal CLI with: ./temporal nexus operation execute --namespace my-caller-namespace --endpoint my-nexus-endpoint --service GreetingNexusService --operation greet --operation-id my-greet-op --input '{"name":"World"}'
Standalone Nexus Operations definition
Standalone Nexus Operations let you run Nexus Operation Executions independently, without being orchestrated by a Workflow. Instead of calling a Nexus Operation from within a Workflow Definition using Workflow.newNexusServiceStub(), you execute a Standalone Nexus Operation directly from a Nexus service client created from a NexusClient using NexusClient.newNexusServiceClient().
Standalone Nexus Operations prerequisites
Standalone Nexus Operations require Java SDK v1.36.1 or above. All APIs are experimental and may be subject to backwards-incompatible changes. They require a Pre-release build of the Temporal CLI that includes Standalone Nexus Operations support. The standard brew install temporal build does not include Standalone Nexus Operation support during Pre-release.
Execute Standalone Nexus Operation synchronously
Create a NexusClient, derive a typed NexusServiceClient from it with newNexusServiceClient(), bound to a specific Nexus Endpoint and Service, then call execute() from application code. The execute() method waits for the Operation to complete and returns the result. It takes a StartNexusOperationOptions where id is required (the SDK never generates one) and scheduleToCloseTimeout is optional, defaulting to the maximum allowed by the Temporal server.
Execute Standalone Nexus Operation example
NexusClient nexusClient = NexusClient.newInstance(stubs, options);
NexusServiceClient<GreetingNexusService> greetingClient =
nexusClient.newNexusServiceClient(GreetingNexusService.class, ENDPOINT_NAME);
// Block until the operation completes and return its result.
GreetingOutput greeting =
greetingClient.execute(
GreetingNexusService::greet,
StartNexusOperationOptions.newBuilder()
.setId("greet-" + UUID.randomUUID())
.setScheduleToCloseTimeout(Duration.ofSeconds(10))
.build(),
new GreetingInput("World"));
Execute Standalone Nexus Operation asynchronously
Call executeAsync() on a NexusServiceClient to execute a Nexus Operation asynchronously. This method returns a CompletableFuture instead of blocking.
Start Standalone Nexus Operation and get handle
Call start() on a NexusServiceClient to start a Standalone Nexus Operation. This returns a NexusOperationHandle. Use NexusOperationHandle.getResult() to wait until the Operation completes and retrieve its result. This works for both synchronous and asynchronous Operations.
NexusOperationHandle.getResult() example
// Start an operation and get a NexusOperationHandle.
NexusOperationHandle<GreetingOutput> handle =
greetingClient.start(
GreetingNexusService::startGreeting, options, new GreetingInput("World"));
// Block until the operation completes and retrieve its result.
GreetingOutput greeting = handle.getResult();
NexusOperationHandle result retrieval methods
If a Standalone Nexus Operation completed successfully, NexusOperationHandle.getResult() returns the result. If the Operation failed, the failure is thrown as a NexusOperationException. Use getResultAsync() for a non-blocking CompletableFuture, or getResult(long timeout, TimeUnit unit) to bound the wait.
List Standalone Nexus Operations
Use NexusClient.listNexusOperationExecutions() to list Standalone Nexus Operation Executions that match a List Filter query. The result is a Stream of operation metadata entries. Note that listNexusOperationExecutions() is called on a NexusClient, not on the typed NexusServiceClient.
Go plugin example with Nexus operation
Example of registering a Nexus operation in a Go plugin:
type WeatherInput struct {
City string `json:"city"`
}
type Weather struct {
City string `json:"city"`
TemperatureRange string `json:"temperatureRange"`
Conditions string `json:"conditions"`
}
var WeatherService = nexus.NewService("weather-service")
var GetWeatherOperation = nexus.NewSyncOperation(
"get-weather",
func(ctx context.Context, input WeatherInput, options nexus.StartOperationOptions) (Weather, error) {
return Weather{
City: input.City,
TemperatureRange: "14-20C",
Conditions: "Sunny with wind.",
}, nil
},
)
func createNexusPlugin() (*temporal.SimplePlugin, error) {
return temporal.NewSimplePlugin(temporal.SimplePluginOptions{
Name: "organization.PluginName",
RunContextBefore: func(ctx context.Context, options temporal.SimplePluginRunContextBeforeOptions) error {
options.Registry.RegisterNexusService(WeatherService)
return nil
},
})
}
DotNet plugin example with Nexus operation
Example of registering a Nexus operation in a DotNet plugin:
[NexusService]
public interface IStringService
{
[NexusOperation]
string DoSomething(string name);
}
[NexusServiceHandler(typeof(IStringService))]
public class HandlerFactoryStringService
{
private readonly Func<IOperationHandler<string, string>> handlerFactory;
public HandlerFactoryStringService(Func<IOperationHandler<string, string>> handlerFactory) =>
this.handlerFactory = handlerFactory;
[NexusOperationHandler]
public IOperationHandler<string, string> DoSomething() => handlerFactory();
}
SimplePlugin nexusPlugin = new SimplePlugin(
"organization.PluginName",
new SimplePluginOptions() { }.AddNexusService(new HandlerFactoryStringService(() =>
OperationHandler.Sync<string, string>((ctx, name) => $"Hello, {name}")))
);
TypeScript plugin example with Nexus operation
Example of registering a Nexus operation in a TypeScript plugin:
const testServiceHandler = nexus.serviceHandler(
nexus.service('testService', {
testSyncOp: nexus.operation<string, string>(),
}),
{
async testSyncOp(_, input) {
return input;
},
},
);
const plugin = new SimplePlugin({
name: 'organization.PluginName',
nexusServices: [testServiceHandler],
});
Java plugin example with Nexus operation
Example of registering a Nexus operation in a Java plugin:
public class WeatherService {
public Weather getWeather(WeatherInput input) {
return new Weather(input.getCity(), "14-20C", "Sunny with wind.");
}
}
public static class Weather {
private final String city;
private final String temperatureRange;
private final String conditions;
public Weather(String city, String temperatureRange, String conditions) {
this.city = city;
this.temperatureRange = temperatureRange;
this.conditions = conditions;
}
}
public static class WeatherInput {
private final String city;
public WeatherInput(String city) {
this.city = city;
}
public String getCity() {
return city;
}
}
SimplePlugin nexusPlugin =
SimplePlugin.newBuilder("organization.PluginName")
.registerNexusServiceImplementation(new WeatherService())
.build();
Python plugin example with Nexus operation
Example of registering a Nexus operation in a Python plugin:
@nexusrpc.service
class WeatherService:
get_weather_nexus_operation: nexusrpc.Operation[WeatherInput, Weather]
@nexusrpc.handler.service_handler(service=WeatherService)
class WeatherServiceHandler:
@nexusrpc.handler.sync_operation
async def get_weather_nexus_operation(
self, ctx: nexusrpc.handler.StartOperationContext, input: WeatherInput
) -> Weather:
return Weather(
city=input.city,
temperature_range="14-20C",
conditions="Sunny with wind.",
)
plugin = SimplePlugin(
"organization.PluginName", nexus_service_handlers=[WeatherServiceHandler()]
)
Temporal Nexus Python SDK documentation sections
The Temporal Nexus Python SDK documentation is organized into three main sections: Quickstart, Feature guide, and Standalone Operations.
Standalone Nexus Operations use same contract and handlers as workflow-driven operations
Standalone Nexus Operations use the same Nexus Service contract, Operation handlers, and Worker setup as Workflow-driven Operations. Only the execution path differs.
list_nexus_operations example
query = f'Endpoint = "{ENDPOINT_NAME}"'
async for op in client.list_nexus_operations(query):
print(
f" OperationId: {op.operation_id},",
f" Operation: {op.operation},",
f" Status: {op.status.name}",
)
execute_operation waits for operation completion
execute_operation waits for the Nexus Operation to complete and returns the result. It requires an id parameter. schedule_to_close_timeout is optional and defaults to the maximum allowed by the Temporal server.
Standalone Nexus Operations require Python SDK 1.30.0+
Standalone Nexus Operations require Python SDK version 1.30.0 or above. All APIs are experimental and may be subject to backwards-incompatible changes.
Define Nexus Service contract with @nexusrpc.service decorator
Use the @nexusrpc.service decorator to declare a service with typed operations. Each operation is a class attribute declared as nexusrpc.Operation[InputType, OutputType]. For example, a service that wraps SayHelloWorkflow returning str would declare say_hello: nexusrpc.Operation[MyInput, str].
Complete Python Nexus quickstart example - full service definition
To define a Nexus Service contract in a file called service.py:
```python
from dataclasses import dataclass
import nexusrpc
@dataclass
class MyInput:
name: str
@nexusrpc.service
class SayHelloNexusService:
say_hello: nexusrpc.Operation[MyInput, str]
```
Caller and handler workflows must be in separate namespaces
In Nexus, the caller Workflow and handler Workflow run in separate Namespaces to provide isolation. A Nexus Endpoint routes requests from the caller Namespace to the handler's target Namespace and Task Queue. The caller Workflow does not import handler code directly, keeping them decoupled so they can live in separate Namespaces, repositories, or teams.
Nexus Operation events in workflow history
When a Workflow invokes a Nexus Operation, the execution history contains NexusOperationScheduled, NexusOperationStarted, and NexusOperationCompleted events. These events can be viewed in the Temporal Web UI to track operation progress.
Rust SDK Temporal Nexus support
The Rust SDK includes support for Temporal Nexus, with a feature guide available at /develop/rust/nexus/feature-guide.
Temporal Nexus TypeScript SDK documentation structure
The Temporal Nexus TypeScript SDK documentation includes three main sections: Quickstart, Feature guide, and Standalone Operations.
Nexus Service contract definition with nexus.service()
A Nexus Service is defined using nexus.service() which declares a named service, and nexus.operation<I, O>() which defines a typed operation with input type I and output type O. The example shows creating a service named 'say-hello' with a 'sayHello' operation that takes MyInput (containing a name string) and returns a string.
Nexus Service decoupling between caller and handler
The caller Workflow only depends on the Service contract (defined in service.ts), not on the handler implementation. This keeps the caller and handler decoupled so they can live in separate Namespaces, repositories, or even teams.
Create Nexus service client for standalone operations
Create a NexusServiceClient using client.nexus.createServiceClient(), bound to a specific Nexus Endpoint and Service. The endpoint must be pre-created on the server. Then call startOperation() or executeOperation() from application code (for example, a starter program), not from inside a Workflow Definition.