# Standalone Nexus Operations

> For the complete documentation index, see [llms.txt](https://docs.temporal.io/llms.txt).
> Any documentation page is available as raw Markdown by appending `.md` to its URL.
> For related questions, query https://docs.temporal.io/api/retrieve?q=<question>&jtb=<job-to-be-done>&src=md-page&agent=<your-name> (no auth; returns JSON `{content, source_url, page_url}`, with `source_url` pointing to Markdown for docs pages). Don't include personal data or credentials.
> If this page is wrong or missing something you needed, or Temporal behaves differently from what it says, report it with https://docs.temporal.io/api/feedback?title=<summary>&message=<what-happened>&category=documentation&page_url=/develop/java/nexus/standalone-operations&src=md-page&agent=<your-name> (use `category=product` when the product, not the page, is wrong). Report only a specific problem you hit, send it once, and don't include personal data or credentials.

> Execute Nexus Operations independently without a Workflow using the Temporal Java SDK.

> **Public Preview**
> Requires Java SDK `v1.36.1` or above. API breaking changes are kept to a minimum before General Availability.

[Standalone Nexus Operations](/standalone-nexus-operation) 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 use the same Nexus Service contract, Operation handlers, and Worker setup as
Workflow-driven Operations — only the execution path differs. See the [Nexus feature guide](/develop/java/nexus/feature-guide) for details on
[defining a Service contract](/develop/java/nexus/feature-guide#define-nexus-service-contract),
[developing Operation handlers](/develop/java/nexus/feature-guide#develop-nexus-service-operation-handlers), and
[registering a Service in a Worker](/develop/java/nexus/feature-guide#register-a-nexus-service-in-a-worker).

This page focuses on the client-side APIs that are unique to Standalone Nexus Operations:

- [Execute a Standalone Nexus Operation](#execute-operation)
- [Start a Standalone Nexus Operation and Wait for the Result](#get-operation-result)
- [List Standalone Nexus Operations](#list-operations)
- [Count Standalone Nexus Operations](#count-operations)
- [Run Standalone Nexus Operations with Temporal Cloud](#run-standalone-nexus-operations-temporal-cloud)

> **📝 Note:**
> The code on this page is in the
> [`java-sandbox/nexus/standalone-operations`](https://github.com/temporalio/documentation-sdk-code-examples/tree/main/java-sandbox/nexus/standalone-operations)
> project, derived from the
> [Java Nexus Standalone sample](https://github.com/temporalio/samples-java/tree/main/core/src/main/java/io/temporal/samples/nexusstandalone).
> Run the commands on this page from that project's folder.
>

## Prerequisites 

Standalone Nexus Operations are a Public Preview feature and require Temporal CLI v1.9.0 or higher.

### 1. Install and verify the Temporal CLI 

The `temporal nexus operation` commands require Temporal CLI v1.9.0 or higher. See
[Temporal CLI support](/standalone-nexus-operation#temporal-cli-support) for install options,
then verify:

```bash
temporal --version
```

Which should output v1.9.0 or higher.

### 2. Start a local dev server 

Start the dev server with Standalone Nexus Operations enabled and the caller and handler Namespaces pre-created:

```bash
temporal server start-dev \
  --namespace my-caller-namespace \
  --namespace my-handler-namespace \
  --dynamic-config-value nexusoperation.enableStandalone=true
```

Without `nexusoperation.enableStandalone=true`, Temporal CLI v1.9.x dev servers reject Standalone Nexus Operations with
`Standalone Nexus operation is disabled`.

The starter and Worker connect to two different Namespaces (a caller Namespace and a handler
Namespace), mirroring how Nexus crosses Namespace boundaries.

To run the examples on this page, create a Nexus Endpoint that routes to the handler Namespace and the Worker's Task Queue:

```bash
temporal operator nexus endpoint create \
  --name my-nexus-endpoint \
  --target-namespace my-handler-namespace \
  --target-task-queue nexus-handler-queue
```

Start the handler Worker in the handler Namespace:

**Maven**

```bash
TEMPORAL_NAMESPACE=my-handler-namespace \
  mvn compile exec:java -Dexec.mainClass=io.temporal.docs.nexus.standaloneoperations.handler.HandlerWorker
```

**Gradle**

```bash
TEMPORAL_NAMESPACE=my-handler-namespace \
  gradle -q execute -PmainClass=io.temporal.docs.nexus.standaloneoperations.handler.HandlerWorker
```

Run the starter in the caller Namespace (from a separate terminal):

**Maven**

```bash
TEMPORAL_NAMESPACE=my-caller-namespace \
  mvn compile exec:java -Dexec.mainClass=io.temporal.docs.nexus.standaloneoperations.StandaloneClientStarter
```

**Gradle**

```bash
TEMPORAL_NAMESPACE=my-caller-namespace \
  gradle -q execute -PmainClass=io.temporal.docs.nexus.standaloneoperations.StandaloneClientStarter
```

The starter runs each example on this page in turn and logs output like the following. Operation IDs are fixed, so the
list and count results grow across runs.

```
execute() returned: Hello, execute!
executeAsync() returned: Hello, executeAsync!
getHandle(id=execute-nexus) then getResult() returned: Hello, execute!
start(id=start-nexus) then getResult() returned: Hello, start!
Started 'to-cancel' id=start-and-cancel-nexus, requesting cancellation
Operation id=start-and-cancel-nexus ended as expected after cancel: Nexus operation failed: operationId='start-and-cancel-nexus'
OperationId: start-and-cancel-nexus, Operation: startGreeting, Status: NEXUS_OPERATION_EXECUTION_STATUS_CANCELED
OperationId: start-nexus, Operation: greet, Status: NEXUS_OPERATION_EXECUTION_STATUS_COMPLETED
OperationId: execute-async-nexus, Operation: greet, Status: NEXUS_OPERATION_EXECUTION_STATUS_COMPLETED
OperationId: execute-nexus, Operation: greet, Status: NEXUS_OPERATION_EXECUTION_STATUS_COMPLETED
Total Nexus operations: 4
  group values=[[Canceled]] count=1
  group values=[[Completed]] count=3
```

## Execute a Standalone Nexus Operation 

To execute a Standalone Nexus Operation, first create a
[`NexusClient`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/NexusClient.html), then
derive a typed
[`NexusServiceClient`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/NexusServiceClient.html)
from it with `newNexusServiceClient()`, bound to a specific Nexus Endpoint and Service. The endpoint must be
pre-created on the server. Then call `start()` or `execute()` from application code (for example, a starter program),
not from inside a Workflow Definition.

<!--SNIPSTART java-nexus-standalone-operations-client-->
[java-sandbox/nexus/standalone-operations/src/main/java/io/temporal/docs/nexus/standaloneoperations/StandaloneClientStarter.java](https://github.com/temporalio/documentation-sdk-code-examples/blob/main/java-sandbox/nexus/standalone-operations/src/main/java/io/temporal/docs/nexus/standaloneoperations/StandaloneClientStarter.java)
```java
// A single NexusClient is the entry point: it serves Visibility queries (list/count) and
// produces service-bound clients.
NexusClient nexusClient =
    NexusClient.newInstance(
        stubs, NexusClientOptions.newBuilder().setNamespace(namespace).build());
// Typed service client: dispatches operations by method reference on the service interface.
NexusServiceClient<GreetingNexusService> greetingClient =
    nexusClient.newNexusServiceClient(GreetingNexusService.class, ENDPOINT_NAME);
```
<!--SNIPEND-->

`execute()` waits for the Operation to complete and returns the result.
Both methods take a [`StartNexusOperationOptions`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/StartNexusOperationOptions.html)
whose `id` is required — the SDK never generates one for you. `scheduleToCloseTimeout` is optional and defaults to the
maximum allowed by the Temporal server.

<!--SNIPSTART java-nexus-standalone-operations-execute {"enable_code_dedenting": true}-->
[java-sandbox/nexus/standalone-operations/src/main/java/io/temporal/docs/nexus/standaloneoperations/StandaloneClientStarter.java](https://github.com/temporalio/documentation-sdk-code-examples/blob/main/java-sandbox/nexus/standalone-operations/src/main/java/io/temporal/docs/nexus/standaloneoperations/StandaloneClientStarter.java)
```java
// execute(...) starts the operation and blocks until it completes, returning the result in one
// call. Used here on the synchronous 'greet' operation.
String operationId = "execute-nexus";
GreetingOutput executed =
    greetingClient.execute(
        GreetingNexusService::greet,
        StartNexusOperationOptions.newBuilder()
            .setId(operationId)
            .setScheduleToCloseTimeout(Duration.ofSeconds(10))
            .build(),
        new GreetingInput("execute"));
logger.info("execute() returned: {}", executed.getMessage());
```
<!--SNIPEND-->

`executeAsync()` is the same but returns a `CompletableFuture` instead of blocking.

<!--SNIPSTART java-nexus-standalone-operations-execute-async {"enable_code_dedenting": true}-->
[java-sandbox/nexus/standalone-operations/src/main/java/io/temporal/docs/nexus/standaloneoperations/StandaloneClientStarter.java](https://github.com/temporalio/documentation-sdk-code-examples/blob/main/java-sandbox/nexus/standalone-operations/src/main/java/io/temporal/docs/nexus/standaloneoperations/StandaloneClientStarter.java)
```java
// executeAsync(...) is the same as execute(...), but returns a CompletableFuture instead of
// blocking.
CompletableFuture<GreetingOutput> future =
    greetingClient.executeAsync(
        GreetingNexusService::greet,
        basicOptions("execute-async-nexus"),
        new GreetingInput("executeAsync"));
GreetingOutput executedAsync = future.get();
logger.info("executeAsync() returned: {}", executedAsync.getMessage());
```
<!--SNIPEND-->

See the full
[starter](https://github.com/temporalio/documentation-sdk-code-examples/blob/main/java-sandbox/nexus/standalone-operations/src/main/java/io/temporal/docs/nexus/standaloneoperations/StandaloneClientStarter.java)
for a complete example that executes, starts, and cancels Operations, gets their results, and lists and counts
Operations.

Or use the Temporal CLI to execute a Standalone Nexus Operation:

```bash
temporal nexus operation execute \
  --namespace my-caller-namespace \
  --endpoint my-nexus-endpoint \
  --service GreetingNexusService \
  --operation greet \
  --operation-id my-greet-op \
  --input '{"name":"World"}'
```

## Start a Standalone Nexus Operation and Wait for the Result 

`start()` returns a
[`NexusOperationHandle`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/NexusOperationHandle.html).
Use `NexusOperationHandle.getResult()` to wait until the Operation completes and retrieve its result. This works for
both synchronous and asynchronous Operations.

<!--SNIPSTART java-nexus-standalone-operations-start {"enable_code_dedenting": true}-->
[java-sandbox/nexus/standalone-operations/src/main/java/io/temporal/docs/nexus/standaloneoperations/StandaloneClientStarter.java](https://github.com/temporalio/documentation-sdk-code-examples/blob/main/java-sandbox/nexus/standalone-operations/src/main/java/io/temporal/docs/nexus/standaloneoperations/StandaloneClientStarter.java)
```java
// start(...) returns a NexusOperationHandle as soon as the operation is started.
NexusOperationHandle<GreetingOutput> handle =
    greetingClient.start(
        GreetingNexusService::greet,
        basicOptions("start-nexus"),
        new GreetingInput("start"));

// getResult() blocks until the operation completes and returns its result.
GreetingOutput greeting = handle.getResult();
logger.info(
    "start(id={}) then getResult() returned: {}",
    handle.getNexusOperationId(),
    greeting.getMessage());
```
<!--SNIPEND-->

If the Operation completed successfully, the result is returned. 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.

Or use the Temporal CLI to wait for a result by Operation ID:

```bash
temporal nexus operation result --namespace my-caller-namespace --operation-id my-greet-op
```

## List Standalone Nexus Operations 

Use [`NexusClient.listNexusOperationExecutions()`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/NexusClient.html)
to list Standalone Nexus Operation Executions that match a [List Filter](/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`.

<!--SNIPSTART java-nexus-standalone-operations-list {"enable_code_dedenting": true}-->
[java-sandbox/nexus/standalone-operations/src/main/java/io/temporal/docs/nexus/standaloneoperations/StandaloneClientStarter.java](https://github.com/temporalio/documentation-sdk-code-examples/blob/main/java-sandbox/nexus/standalone-operations/src/main/java/io/temporal/docs/nexus/standaloneoperations/StandaloneClientStarter.java)
```java
// listNexusOperationExecutions accepts a List Filter query. Here it filters by the built-in
// Endpoint attribute. Query syntax is documented at https://docs.temporal.io/list-filter .
String query = "Endpoint = \"" + endpointName + "\"";
List<NexusOperationExecutionMetadata> operations =
    nexusClient.listNexusOperationExecutions(query).collect(Collectors.toList());
for (NexusOperationExecutionMetadata op : operations) {
  logger.info(
      "OperationId: {}, Operation: {}, Status: {}",
      op.getOperationId(),
      op.getOperation(),
      op.getStatus());
}
```
<!--SNIPEND-->

The `query` parameter accepts [List Filter](/list-filter) syntax. For example,
`"Endpoint = 'my-endpoint' AND ExecutionStatus = 'Running'"`.

Or use the Temporal CLI:

```bash
temporal nexus operation list --namespace my-caller-namespace --query 'Endpoint = "my-nexus-endpoint"'
```

## Count Standalone Nexus Operations 

Use [`NexusClient.countNexusOperationExecutions()`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/client/NexusClient.html)
to count Standalone Nexus Operation Executions that match a [List Filter](/list-filter) query.

Note that `countNexusOperationExecutions()` is called on a `NexusClient`, not on the typed `NexusServiceClient`.

<!--SNIPSTART java-nexus-standalone-operations-count {"enable_code_dedenting": true}-->
[java-sandbox/nexus/standalone-operations/src/main/java/io/temporal/docs/nexus/standaloneoperations/StandaloneClientStarter.java](https://github.com/temporalio/documentation-sdk-code-examples/blob/main/java-sandbox/nexus/standalone-operations/src/main/java/io/temporal/docs/nexus/standaloneoperations/StandaloneClientStarter.java)
```java
// countNexusOperationExecutions accepts the same List Filter query.
NexusOperationExecutionCount total = nexusClient.countNexusOperationExecutions(query);
logger.info("Total Nexus operations: {}", total.getCount());

// A GROUP BY query returns a count per group value.
NexusOperationExecutionCount grouped =
    nexusClient.countNexusOperationExecutions(query + " GROUP BY ExecutionStatus");
for (NexusOperationExecutionCount.AggregationGroup group : grouped.getGroups()) {
  logger.info("  group values={} count={}", group.getGroupValues(), group.getCount());
}
```
<!--SNIPEND-->

A query that ends in a `GROUP BY` clause (for example, `GROUP BY ExecutionStatus`) returns a count per group, available
through `NexusOperationExecutionCount.getGroups()`.

Or use the Temporal CLI:

```bash
temporal nexus operation count --namespace my-caller-namespace --query 'Endpoint = "my-nexus-endpoint"'
```

## Run Standalone Nexus Operations with Temporal Cloud 

The code samples referenced on this page build their client from a `ClientConfigProfile` loaded from a TOML profile, so
the same code works against Temporal Cloud. Point the profile at your Cloud Namespace (or override the connection
via `TEMPORAL_*` environment variables). No code changes are needed.

For full details on connecting to Temporal Cloud, including Namespace creation, Nexus Endpoint setup, certificate
generation, and authentication options, see
[Make Nexus calls across Namespaces in Temporal Cloud](/develop/java/nexus/feature-guide#nexus-calls-across-namespaces-temporal-cloud)
and [Connect to Temporal Cloud](/develop/java/client/temporal-client#connect-to-temporal-cloud).
