# Cloud profile for Temporal Cloud
[profile.staging]
address = "your-namespace.a1b2c.tmprl.cloud:7233"
namespace = "your-namespace"
api_key = "your-api-key-here"
```

Use the `loadClientConnectConfig` helper from `@temporalio/envconfig` to load the `staging` profile from the
configuration file and create a `NativeConnection` object as follows:

```ts {1,15,17}

async function main() {
  const configFile = resolve(__dirname, '../config.toml');
  const profileName = 'staging'

  // Load the 'staging' profile.
  const config = loadClientConnectConfig({
    profile: profileName,
    configSource: { path: configFile },
  });

  const connection = await NativeConnection.connect(config.connectionOptions);

  const worker = await Worker.create({
    connection,
    namespace: <namespace_id>.<account_id>,
    // ...
});
}
```

</TabItem>

<TabItem value="env-vars" label="Environment Variables">

Ensure you have set the necessary environment variables to connect to Temporal Cloud. For example:

```bash
export TEMPORAL_NAMESPACE="your-namespace.your-account-id"
export TEMPORAL_ADDRESS="your-namespace.a1b2c.tmprl.cloud:7233"
export TEMPORAL_TLS_CLIENT_CERT_PATH="/path/to/your/client/cert.pem"
export TEMPORAL_TLS_CLIENT_KEY_PATH="/path/to/your/client/key.pem"
```

After setting the environment variables, use the following code to create a `NativeConnection` object using the
`loadClientConnectConfig` helper from `@temporalio/envconfig`:

```ts {1,5}

async function main() {
  const config = loadClientConnectConfig();

  const connection = await NativeConnection.connect(config.connectionOptions);

  const worker = await Worker.create({
    connection,
    namespace: process.env.TEMPORAL_NAMESPACE,
    // ...
  });
}
```

</TabItem>

<TabItem value="code" label="Code">

You can also provide connections options in your TypeScript code directly. To create an initial connection, provide the
connections to the ` NativeConnection.connect` method, and then pass the resulting `NativeConnection` object to
`Worker.create()` when creating the Worker:

```ts {1,4,9}

const connection = await NativeConnection.connect({
    address: <endpoint>,
    tls: true,
    apiKey: <APIKey>,
});
const worker = await Worker.create({
    connection,
    namespace: <namespace_id>.<account_id>,
    // ...
});
```

</TabItem>

</Tabs>

## NativeConnection, Connection, and Client

`NativeConnection`, `Connection`, and `Client` are all classes provided by the TypeScript SDK to facilitate
communication with the Temporal Service. This section explains the differences between these classes and their
respective use cases. For detailed information about each class, refer to the
[Temporal TypeScript API documentation](https://typescript.temporal.io/api/namespaces/client).

### NativeConnection vs. Connection {#native-connection-vs-connection}

The TypeScript SDK provides two types of connection classes to connect to the Temporal Service: `NativeConnection` and
`Connection`. The `NativeConnection` class is used to connect from a Worker, while the `Connection` class is used to
connect from a Temporal Application or from within an Activity, typically through a `Client` object. Both connection
classes accept the same set of connection options.

### Connection vs. Client {#connection-vs-client}

A `Client` object is a high-level, lightweight abstraction that simplifies interaction with the Temporal Service. It
internally manages a `Connection` object to handle the low-level communication details. The `Client` class provides
convenient methods for common operations such as starting Workflow Executions, sending Signals and Queries, and
retrieving Workflow results.

A `Connection` object is a lower-level and expensive object that represents a direct connection to the Temporal Service.
You pass in a `Connection` object to the `Client` constructor to create a `Client` instance. Since a `Connection` is
expensive to create, create a single `Connection` object and reuse it across your application whenever possible.

When instantiating a `Connection`, you specify most connection options except for the Namespace, such as the Temporal
Service endpoint, TLS settings, and authentication credentials. When instantiating a `Client`, you provide the
`Connection` object and the Namespace you want to connect to, along with other client options.

## Start Workflow Execution {#start-workflow-execution}

**How to start a Workflow Execution using the Typescript SDK**

[Workflow Execution](/workflow-execution) semantics rely on several parameters—that is, to start a Workflow Execution
you must supply a Task Queue that will be used for the Tasks (one that a Worker is polling), the Workflow Type,
language-specific contextual data, and Workflow Function parameters.

In the examples below, all Workflow Executions are started using a Temporal Client. To spawn Workflow Executions from
within another Workflow Execution, use either the Child Workflow or External Workflow APIs.

See the [Customize Workflow Type](/develop/typescript/core-application#workflow-type) section to see how to customize
the name of the Workflow Type.

A request to spawn a Workflow Execution causes the Temporal Service to create the first Event
([WorkflowExecutionStarted](/references/events#workflowexecutionstarted)) in the Workflow Execution Event History. The
Temporal Service then creates the first Workflow Task, resulting in the first
[WorkflowTaskScheduled](/references/events#workflowtaskscheduled) Event.

When you have a Client, you can schedule the start of a Workflow with `client.workflow.start()`, specifying
`workflowId`, `taskQueue`, and `args` and returning a Workflow handle immediately after the Server acknowledges the
receipt.

```typescript
const handle = await client.workflow.start(example, {
  workflowId: 'your-workflow-id',
  taskQueue: 'your-task-queue',
  args: ['argument01', 'argument02', 'argument03'], // this is typechecked against workflowFn's args
});
const handle = client.getHandle(workflowId);
const result = await handle.result();
```

Calling `client.workflow.start()` and `client.workflow.execute()` send a command to Temporal Server to schedule a new
Workflow Execution on the specified Task Queue. It does not actually start until a Worker that has a matching Workflow
Type, polling that Task Queue, picks it up.

You can test this by executing a Client command without a matching Worker. Temporal Server records the command in Event
History, but does not make progress with the Workflow Execution until a Worker starts polling with a matching Task Queue
and Workflow Definition.

Workflow Execution run in a separate V8 isolate context in order to provide a
[deterministic runtime](/workflow-definition#deterministic-constraints).

### Set a Workflow's Task Queue {#set-task-queue}

In most SDKs, the only Workflow Option that must be set is the name of the [Task Queue](/task-queue).

For any code to execute, a Worker Process must be running that contains a Worker Entity that is polling the same Task
Queue name.

A Task Queue is a dynamic queue in Temporal polled by one or more Workers.

Workers bundle Workflow code and node modules using Webpack v5 and execute them inside V8 isolates. Activities are
directly required and run by Workers in the Node.js environment.

Workers are flexible. You can host any or all of your Workflows and Activities on a Worker, and you can host multiple
Workers on a single machine.

The Worker need three main things:

- `taskQueue`: The Task Queue to poll. This is the only required argument.
- `activities`: Optional. Imported and supplied directly to the Worker.
- Workflow bundle. Choose one of the following options:
  - Specify `workflowsPath` pointing to your `workflows.ts` file to pass to Webpack; for example,
    `require.resolve('./workflows')`. Workflows are bundled with their dependencies.
  - If you prefer to handle the bundling yourself, pass a prebuilt bundle to `workflowBundle`.

```ts

async function run() {
  // Step 1: Register Workflows and Activities with the Worker and connect to
  // the Temporal server.
  const worker = await Worker.create({
    workflowsPath: require.resolve('./workflows'),
    activities,
    taskQueue: 'hello-world',
  });
  // Worker connects to localhost by default and uses console.error for logging.
  // Customize the Worker by passing more options to create():
  // https://typescript.temporal.io/api/classes/worker.Worker
  // If you need to configure server connection parameters, see docs:
  // /typescript/security#encryption-in-transit-with-mtls

  // Step 2: Start accepting tasks on the `tutorial` queue
  await worker.run();
}

run().catch((err) => {
  console.error(err);
  process.exit(1);
});
```

`taskQueue` is the only required option; however, use `workflowsPath` and `activities` to register Workflows and
Activities with the Worker.

When scheduling a Workflow, you must specify `taskQueue`.

```ts

// This is the code that is used to start a Workflow.
const connection = await Connection.create();
const client = new Client({ connection });
const result = await client.workflow.execute(yourWorkflow, {
  // required
  taskQueue: 'your-task-queue',
  // required
  workflowId: 'your-workflow-id',
});
```

When creating a Worker, you must pass the `taskQueue` option to the `Worker.create()` function.

```ts
const worker = await Worker.create({
  // imported elsewhere
  activities,
  taskQueue: 'your-task-queue',
});
```

Optionally, in Workflow code, when calling an Activity, you can specify the Task Queue by passing the `taskQueue` option
to `proxyActivities()`, `startChild()`, or `executeChild()`. If you do not specify `taskQueue`, the TypeScript SDK
places Activity and Child Workflow Tasks in the same Task Queue as the Workflow Task Queue.

### Set a Workflow Id {#workflow-id}

Although it is not required, we recommend providing your own
[Workflow Id](/workflow-execution/workflowid-runid#workflow-id)that maps to a business process or business entity
identifier, such as an order identifier or customer identifier.

Connect to a Client with `client.workflow.start()` and any arguments. Then specify your `taskQueue` and set your
`workflowId` to a meaningful business identifier.

```typescript
const handle = await client.workflow.start(example, {
  workflowId: 'yourWorkflowId',
  taskQueue: 'yourTaskQueue',
  args: ['your', 'arg', 'uments'],
});
```

This starts a new Client with the given Workflow Id, Task Queue name, and an argument.

### Get the results of a Workflow Execution {#get-workflow-results}

If the call to start a Workflow Execution is successful, you will gain access to the Workflow Execution's Run Id.

The Workflow Id, Run Id, and Namespace may be used to uniquely identify a Workflow Execution in the system and get its
result.

It's possible to both block progress on the result (synchronous execution) or get the result at some other point in time
(asynchronous execution).

In the Temporal Platform, it's also acceptable to use Queries as the preferred method for accessing the state and
results of Workflow Executions.

To return the results of a Workflow Execution:

```typescript
return 'Completed ' + wf.workflowInfo().workflowId + ', Total Charged: ' + totalCharged;
```

`totalCharged` is just a function declared in your code. For a full example, see
[subscription-workflow-project-template-typescript/src/workflows.ts](https://github.com/temporalio/subscription-workflow-project-template-typescript/blob/main/src/workflows.ts).

A Workflow function may return a result. If it doesn’t (in which case the return type is `Promise<void>`), the result
will be `undefined`.

If you started a Workflow with `client.workflow.start()`, you can choose to wait for the result anytime with
`handle.result()`.

```typescript
const handle = client.getHandle(workflowId);
const result = await handle.result();
```

Using a Workflow Handle isn't necessary with `client.workflow.execute()`.

Workflows that prematurely end will throw a `WorkflowFailedError` if you call `result()`.

If you call `result()` on a Workflow that prematurely ended for some reason, it throws a
[`WorkflowFailedError` error](https://typescript.temporal.io/api/classes/client.WorkflowFailedError/) that reflects the
reason. For that reason, it is recommended to catch that error.

```typescript
const handle = client.getHandle(workflowId);
try {
  const result = await handle.result();
} catch (err) {
  if (err instanceof WorkflowFailedError) {
    throw new Error('Temporal workflow failed: ' + workflowId, {
      cause: err,
    });
  } else {
    throw new Error('error from Temporal workflow ' + workflowId, {
      cause: err,
    });
  }
}
```

---

## Temporal Nexus - TypeScript SDK Feature Guide

:::tip SUPPORT, STABILITY, and DEPENDENCY INFO

Temporal TypeScript SDK support for Nexus is at [Pre-release](/evaluate/development-production-features/release-stages#pre-release).

All APIs are experimental and may be subject to backwards-incompatible changes.

:::

Use [Temporal Nexus](/evaluate/nexus) to connect Temporal Applications within and across Namespaces using a Nexus Endpoint, a Nexus Service contract, and Nexus Operations.

This page shows how to do the following:

- [Run a development Temporal Service with Nexus enabled](#run-the-temporal-nexus-development-server)
- [Create caller and handler Namespaces](#create-caller-handler-namespaces)
- [Create a Nexus Endpoint to route requests from caller to handler](#create-nexus-endpoint)
- [Define the Nexus Service contract](#define-nexus-service-contract)
- [Develop a Nexus Service and Operation handlers](#develop-nexus-service-operation-handlers)
- [Develop a caller Workflow that uses a Nexus Service](#develop-caller-workflow-nexus-service)
- [Understand exceptions in Nexus Operations](#exceptions-in-nexus-operations)
- [Cancel a Nexus Operation](#canceling-a-nexus-operation)
- [Make Nexus calls across Namespaces in Temporal Cloud](#nexus-calls-across-namespaces-temporal-cloud)

:::note

This documentation uses source code derived from the [TypeScript Nexus sample](https://github.com/temporalio/samples-typescript/tree/main/nexus-hello).

:::

## Run the Temporal Development Server with Nexus enabled {#run-the-temporal-nexus-development-server}

Prerequisites:

- [Install the latest Temporal CLI](https://learn.temporal.io/getting_started/typescript/dev_environment/#set-up-a-local-temporal-service-for-development-with-temporal-cli) (`v1.3.0` or higher recommended)
- [Install the latest Temporal TypeScript SDK](https://learn.temporal.io/getting_started/typescript/dev_environment/#add-temporal-typescript-sdk-dependencies) (`v1.12.3` or higher)

The first step in working with Temporal Nexus involves starting a Temporal Server with Nexus enabled.

```
temporal server start-dev
```

This command automatically starts the Temporal development server with the Web UI, and creates the `default` Namespace. It uses an in-memory database, so do not use it for real use cases.

The Temporal Web UI should now be accessible at [http://localhost:8233](http://localhost:8233), and the Temporal Server should now be available for client connections on `localhost:7233`.

## Create caller and handler Namespaces {#create-caller-handler-namespaces}

Before setting up Nexus endpoints, create separate Namespaces for the caller and handler.

```
temporal operator namespace create --namespace my-target-namespace
temporal operator namespace create --namespace my-caller-namespace
```

For this example, `my-target-namespace` will contain the Nexus Operation handler, and you will use a Workflow in `my-caller-namespace` to call that Operation handler.
We use different namespaces to demonstrate cross-Namespace Nexus calls.

## Create a Nexus Endpoint to route requests from caller to handler {#create-nexus-endpoint}

After establishing caller and handler Namespaces, the next step is to create a Nexus Endpoint to route requests.

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

You can also use the Web UI to create the Namespaces and Nexus endpoint.

## Define the Nexus Service contract {#define-nexus-service-contract}

Defining a clear contract for the Nexus Service is crucial for smooth communication.

In this example, there is a service package that describes the Service and Operation names along with input/output types for caller Workflows to use the Nexus Endpoint.

Each [Temporal SDK includes and uses a default Data Converter](https://docs.temporal.io/dataconversion).
The default data converter encodes payloads in the following order: Null, Byte array, and JSON.
In a polyglot environment, that is where more than one language and SDK is being used to develop a Temporal solution, JSON is a common choice.
This example uses plain TypeScript objects, serialized into JSON.

Note: By default, the TypeScript SDK [does not support Protobuf JSON encoding](https://typescript.temporal.io/api/interfaces/common.PayloadConverter). If passing Protobuf payloads use the [ProtobufJsonPayloadConverter](https://typescript.temporal.io/api/classes/protobufs.ProtobufJsonPayloadConverter) instead.

<!--SNIPSTART typescript-nexus-hello-service-->
[nexus-hello/src/api.ts](https://github.com/temporalio/samples-typescript/blob/main/nexus-hello/src/api.ts)
```ts

export const helloService = nexus.service('hello', {
  /**
   * Return the input message, unmodified. In the present sample, this Operation
   * will be implemented using the Synchronous Nexus Operation handler syntax.
   */
  echo: nexus.operation<EchoInput, EchoOutput>(),

  /**
   * Return a salutation message, in the requested language. In the present sample,
   * this Operation will be implemented by starting the `helloWorkflow` Workflow.
   */
  hello: nexus.operation<HelloInput, HelloOutput>(),
});

export interface EchoInput {
  message: string;
}

export interface EchoOutput {
  message: string;
}

export interface HelloInput {
  name: string;
  language: LanguageCode;
}

export interface HelloOutput {
  message: string;
}

export type LanguageCode = 'en' | 'fr' | 'de' | 'es' | 'tr';
```
<!--SNIPEND-->

## Develop a Nexus Service handler and Operation handlers {#develop-nexus-service-operation-handlers}

A Nexus Service handler is defined using the `nexus-rpc`'s [`serviceHandler`](https://nexus-rpc.github.io/sdk-typescript/functions/serviceHandler.html) function. {/* Added */}
Nexus Service handlers are typically defined in the same Worker as the underlying Temporal primitives they abstract.
A Service handler must provide Operation handlers for each Operation declared by the Service. {/* Added */}
Operation handlers can decide if a given Nexus Operation will be synchronous or asynchronous.
They can execute arbitrary code, and invoke underlying Temporal primitives such as a Workflow, Query, Signal, or Update.

The `@temporalio/nexus` package provides utilities to help create Nexus Operations that interracts with a Temporal namespace: {/* Extended */}

- `WorkflowRunOperationHandler` - Create an asynchronous operation handler that starts a Workflow.
- `getClient()` - Get a Temporal Client connected using the same `NativeConnection` as the present Temporal Worker.
  It can be used to implement synchronous handlers backed by Temporal primitives such as Signals and Queries.

### Develop a Synchronous Nexus Operation handler

Simple RPC handlers can be implemented as synchronous Nexus Operation handlers, which is defined in TypeScript as a simple async function. {/* sync operation vs async func is very confusing in this context */}
The handler function can obtain a Temporal Client, using `getClient()`, which can be used for signaling, querying, and listing Workflows.
However, implementations are free to make arbitrary calls to other services or databases, or perform computations such as this one:

<!--SNIPSTART typescript-nexus-hello-service-handler {"selectedLines": ["2","4","6-17","37"]}-->
[nexus-hello/src/service/handler.ts](https://github.com/temporalio/samples-typescript/blob/main/nexus-hello/src/service/handler.ts)
```ts
// ...

// ...

// ...

export const helloServiceHandler = nexus.serviceHandler(helloService, {
  echo: async (ctx, input: EchoInput): Promise<EchoOutput> => {
    // A simple async function can be used to defined a Synchronous Nexus Operation.
    // This is often sufficient for Operations that simply make arbitrary short calls to
    // other services or databases, or that perform simple computations such as this one.
    //
    // You may also access a Temporal Client by calling `temporalNexus.getClient()`.
    // That Client can be used to make arbitrary calls, such as signaling, querying,
    // or listing workflows.
    return input;
  },
// ...
});
```
<!--SNIPEND-->

### Develop an Asynchronous Nexus Operation handler to start a Workflow

Use `@temporalio/nexus`'s `WorkflowRunOperationHandler` helper class to easily expose a Temporal Workflow as a Nexus Operation.
Note that even though a Nexus operation can only take one input parameter, if you need to pass
multiple arguments through to the workflow, you can do so by using multiple properties of the input object, and placing them in
the array provided to the `args` option when calling `startWorkflow`.

<!--SNIPSTART typescript-nexus-hello-service-handler {"selectedLines": ["1-7","18-37"]}-->
[nexus-hello/src/service/handler.ts](https://github.com/temporalio/samples-typescript/blob/main/nexus-hello/src/service/handler.ts)
```ts

export const helloServiceHandler = nexus.serviceHandler(helloService, {
// ...
  hello: new temporalNexus.WorkflowRunOperationHandler<HelloInput, HelloOutput>(
    // WorkflowRunOperationHandler takes a function that receives the Operation's context and input.
    // That function can be used to validate and/or transform the input before passing it to
    // the Workflow, as well as to customize various Workflow start options as appropriate.
    // Call temporalNexus.startWorkflow() to actually start the Workflow from inside the
    // WorkflowRunOperationHandler's delegate function.
    async (ctx, input: HelloInput) => {
      return await temporalNexus.startWorkflow(ctx, helloWorkflow, {
        args: [input],

        // Workflow IDs should typically be business-meaningful IDs and are used to dedupe workflow starts.
        // For this example, we're using the request ID allocated by Temporal when the caller workflow schedules
        // the operation, this ID is guaranteed to be stable across retries of this operation.
        workflowId: ctx.requestId ?? randomUUID(),

        // Task queue defaults to the task queue this Operation is handled on.
      });
    },
  ),
});
```
<!--SNIPEND-->

Workflow IDs should typically be business-meaningful IDs and are used to dedupe Workflow starts.
In general, the ID should be passed in the Operation input as part of the Nexus Service contract.

:::tip RESOURCES

[Attach multiple Nexus callers to a handler Workflow](/nexus/operations#attaching-multiple-nexus-callers) with a Conflict-Policy of Use-Existing.

:::

### Register your Nexus Service handler in a Worker

After developing an asynchronous Nexus Operation handler to start a Workflow, the next step is to register your Nexus Service handler in a Worker.

<!--SNIPSTART typescript-nexus-hello-service-worker {"selectedLines": ["1-3","9-17"]}-->
[nexus-hello/src/service/worker.ts](https://github.com/temporalio/samples-typescript/blob/main/nexus-hello/src/service/worker.ts)
```ts

// ...
    const namespace = 'my-target-namespace';
    const serviceTaskQueue = 'my-handler-task-queue';
    const worker = await Worker.create({
      connection,
      namespace,
      taskQueue: serviceTaskQueue,
      workflowsPath: require.resolve('./workflows'),
      nexusServices: [helloServiceHandler],
    });
```
<!--SNIPEND-->

## Develop a caller Workflow that uses the Nexus Service {#develop-caller-workflow-nexus-service}

To execute a Nexus Operation from a Workflow, import the necessary service definition types, then use `@temporalio/workflow`'s `createNexusClient` to create a Nexus client for that service.
You will need to provide the Nexus Endpoint name, which you registered previously in [Create a Nexus Endpoint to route requests from caller to handler](#create-nexus-endpoint).

<!--SNIPSTART typescript-nexus-hello-service-caller-workflow {"selectedLines": ["1-5","21-34"]}-->

[nexus-hello/src/caller/workflows.ts](https://github.com/temporalio/samples-typescript/blob/main/nexus-hello/src/caller/workflows.ts)

```ts

const HELLO_SERVICE_ENDPOINT = "hello-service-endpoint-name";

export async function helloCallerWorkflow(name: string, language: LanguageCode): Promise<string> {
  const nexusClient = wf.createNexusClient({
    service: helloService,
    endpoint: HELLO_SERVICE_ENDPOINT,
  });

  const helloResult = await nexusClient.executeOperation(
    "hello",
    { name, language },
    { scheduleToCloseTimeout: "10s" }
  );

  return helloResult.message;
}
```

<!--SNIPEND-->

### Register the caller Workflow in a Worker and start the caller Workflow

This Workflow can be registered with a Worker and started using `client.startWorkflow()` or `client.executeWorkflow()`, as usual.
Refer to the [complete TypeScript sample](https://github.com/temporalio/samples-typescript/blob/main/nexus-hello) for reference.

- [nexus-hello/src/caller/worker.ts](https://github.com/temporalio/samples-typescript/blob/main/nexus-hello/src/caller/worker.ts) shows how to register the caller Workflow in a Worker and run the Worker.
- [nexus-hello/src/starter.ts](https://github.com/temporalio/samples-typescript/blob/main/nexus-hello/src/starter.ts) shows how to use a Temporal Client to execute the sample caller Workflow.

## Exceptions in Nexus operations {#exceptions-in-nexus-operations}

Temporal provides general guidance on [Errors in Nexus operations](https://docs.temporal.io/references/failures#errors-in-nexus-operations).
In TypeScript, there are three Nexus-specific exception classes:

- `nexus-rpc`'s [`OperationError`](https://nexus-rpc.github.io/sdk-typescript/classes/OperationError.html): this is the exception type you should throw in a Nexus operation to indicate that it has failed according to its own application logic and should not be retried.
- `nexus-rpc`'s [`HandlerError`](https://nexus-rpc.github.io/sdk-typescript/classes/HandlerError.html): you can throw this exception type in a Nexus operation with a specific [HandlerErrorType](https://nexus-rpc.github.io/sdk-typescript/types/HandlerErrorType.html). The error will be marked as either retryable or non-retryable according to the type, following the [Nexus spec](https://github.com/nexus-rpc/api/blob/main/SPEC.md#predefined-handler-errors). The non-retryable handler error types are `BAD_REQUEST`, `UNAUTHENTICATED`, `UNAUTHORIZED`, `NOT_FOUND`, `NOT_IMPLEMENTED`; the retryable types are `RESOURCE_EXHAUSTED`, `INTERNAL`, `UNAVAILABLE`, `UPSTREAM_TIMEOUT`.
- `@temporalio/nexus`'s [`NexusOperationFailure`](https://typescript.temporal.io/api/classes/common.NexusOperationFailure): this is the error thrown inside a Workflow when a Nexus operation fails for any reason. Use the `cause` attribute on the exception to access the cause chain.

## Canceling a Nexus Operation {#canceling-a-nexus-operation}

Nexus Operations, just like other cancellable APIs provided by the `@temporalio/workflow` package, execute within Cancellation Scopes.
Requesting cancellation of a Cancellation Scope results in requesting cancellation for all cancellable operations owned by that scope.
The Workflow itself defines the root Cancellation Scope.
Requesting cancellation of the Workflow therefore propagates the cancellation request to all cancellable operations started by that workflow, including Nexus Operations.

To provide more granular control over cancellation of a specific Nexus Operation, you may explicitly create a new Cancellation Scope, and start the Nexus Operation from within that scope.
An example demonstrating this can be found at our [nexus cancellation sample](https://github.com/temporalio/samples-typescript/tree/main/nexus-cancellation).

Only asynchronous operations can be canceled in Nexus, since cancellation is sent using an operation token.
The Workflow or other resources backing the operation may choose to ignore the cancellation request.

Once the caller Workflow completes, the caller's Nexus Machinery will not make any further attempts to cancel operations that are still running.
It's okay to leave operations running in some use cases.
To ensure cancellations are delivered, wait for all pending operations to finish before exiting the Workflow.

## Make Nexus calls across Namespaces in Temporal Cloud {#nexus-calls-across-namespaces-temporal-cloud}

This section assumes you are already familiar with how to connect a Worker to Temporal Cloud.
The `tcld` CLI is used to create Namespaces and the Nexus Endpoint, and mTLS client certificates will be used to securely connect the caller and handler Workers to their respective Temporal Cloud Namespaces.

### Install the latest `tcld` CLI and generate certificates

To install the latest version of the `tcld` CLI, run the following command (on macOS):

```
brew install temporalio/brew/tcld
```

If you don't already have certificates, you can generate them for mTLS Worker authentication using the command below:

```
tcld gen ca --org $YOUR_ORG_NAME --validity-period 1y --ca-cert ca.pem --ca-key ca.key
```

These certificates will be valid for one year.

### Create caller and handler Namespaces

Before deploying to Temporal Cloud, ensure that the appropriate Namespaces are created for both the caller and handler.
If you already have these Namespaces, you don't need to do this.

```
tcld login

tcld namespace create \
	--namespace <your-caller-namespace> \
	--cloud-provider aws \
	--region us-west-2 \
	--ca-certificate-file 'path/to/your/ca.pem' \
	--retention-days 1

tcld namespace create \
	--namespace <your-target-namespace> \
	--cloud-provider aws \
	--region us-west-2 \
	--ca-certificate-file 'path/to/your/ca.pem' \
	--retention-days 1
```

Alternatively, you can create Namespaces through the UI: [https://cloud.temporal.io/namespaces](https://cloud.temporal.io/namespaces).

### Create a Nexus Endpoint to route requests from caller to handler

To create a Nexus Endpoint you must have a Developer account role or higher, and have NamespaceAdmin permission on the `--target-namespace`.

```
tcld nexus endpoint create \
  --name <my-nexus-endpoint-name> \
  --target-task-queue my-handler-task-queue \
  --target-namespace <my-target-namespace.account> \
  --allow-namespace <my-caller-namespace.account> \
  --description-file description.md
```

The `--allow-namespace` is used to build an Endpoint allowlist of caller Namespaces that can use the Nexus Endpoint, as described in Runtime Access Control.

Alternatively, you can create a Nexus Endpoint through the UI: [https://cloud.temporal.io/nexus](https://cloud.temporal.io/nexus).

## Observability

### Web UI

A synchronous Nexus Operation will surface in the caller Workflow as follows, with just `NexusOperationScheduled` and `NexusOperationCompleted` events in the caller's Workflow history:

<CaptionedImage src="/img/cloud/nexus/go-sdk-observability-sync.png" title="Observability Sync" />

An asynchronous Nexus Operation will surface in the caller Workflow as follows, with `NexusOperationScheduled`, `NexusOperationStarted`, and `NexusOperationCompleted`, in the caller's Workflow history:

<CaptionedImage src="/img/cloud/nexus/go-sdk-observability-async.png" title="Observability Async" />

### Temporal CLI

Use the `workflow describe` command to show pending Nexus Operations in the caller Workflow and any attached callbacks on the handler Workflow:

```
temporal workflow describe -w <ID>
```

Nexus events are included in the caller's Workflow history:

```
temporal workflow show -w <ID>
```

For **asynchronous Nexus Operations** the following are reported in the caller's history:

- `NexusOperationScheduled`
- `NexusOperationStarted`
- `NexusOperationCompleted`

For **synchronous Nexus Operations** the following are reported in the caller's history:

- `NexusOperationScheduled`
- `NexusOperationCompleted`

:::note

`NexusOperationStarted` isn't reported in the caller's history for synchronous operations.

:::

## Learn more

- Read the high-level description of the [Temporal Nexus feature](/evaluate/nexus) and watch the [Nexus keynote and demo](https://youtu.be/qqc2vsv1mrU?feature=shared&t=2082).
- Learn how Nexus works in the [Nexus deep dive talk](https://www.youtube.com/watch?v=izR9dQ_eIe4) and [Encyclopedia](/nexus).
- Deploy Nexus Endpoints in production with [Temporal Cloud](/cloud/nexus).

---

## Testing - TypeScript SDK

The Testing section of the Temporal Application development guide describes the frameworks that facilitate Workflow and integration testing.

In the context of Temporal, you can create these types of automated tests:

- **End-to-end:** Running a Temporal Server and Worker with all its Workflows and Activities; starting and interacting with Workflows from a Client.
- **Integration:** Anything between end-to-end and unit testing.
  - Running Activities with mocked Context and other SDK imports (and usually network requests).
  - Running Workers with mock Activities, and using a Client to start Workflows.
  - Running Workflows with mocked SDK imports.
- **Unit:** Running a piece of Workflow or Activity code (a function or method) and mocking any code it calls.

We generally recommend writing the majority of your tests as integration tests.

Because the test server supports skipping time, use the test server for both end-to-end and integration tests with Workers.

## Test frameworks {#test-frameworks}

Some SDKs have support or examples for popular test frameworks, runners, or libraries.

TypeScript has sample tests for [Jest](https://jestjs.io/) and [Mocha](https://mochajs.org/).

**Jest**

- Minimum Jest version: `27.0.0`
- [Sample test file](https://github.com/temporalio/samples-typescript/blob/main/activities-examples/src/workflows.test.ts)
- [`jest.config.js`](https://github.com/temporalio/samples-typescript/blob/main/activities-examples/jest.config.js) (must use [`testEnvironment: 'node'`](https://jestjs.io/docs/configuration#testenvironment-string); `testEnvironment: 'jsdom'` is not supported)

**Mocha**

- [Sample test file](https://github.com/temporalio/samples-typescript/blob/main/activities-examples/src/mocha/workflows.test.ts)
- Test coverage library: [`@temporalio/nyc-test-coverage`](https://github.com/temporalio/sdk-typescript/tree/main/packages/nyc-test-coverage)

## Testing Activities {#test-activities}

An Activity can be tested with a mock Activity environment, which provides a way to mock the Activity context, listen to Heartbeats, and cancel the Activity.
This behavior allows you to test the Activity in isolation by calling it directly, without needing to create a Worker to run the Activity.

### Run an Activity {#run-an-activity}

If an Activity references its context, you need to mock that context when testing in isolation.

First, create a [`MockActivityEnvironment`](https://typescript.temporal.io/api/classes/testing.MockActivityEnvironment).
The constructor accepts an optional partial Activity [`Info`](https://typescript.temporal.io/api/interfaces/activity.Info) object in case any info fields are needed for the test.

Then use [`MockActivityEnvironment.run()`](https://typescript.temporal.io/api/classes/testing.MockActivityEnvironment#run) to run a function in an Activity [Context](https://typescript.temporal.io/api/classes/activity.Context).

```ts

// A function that takes two numbers and returns a promise that resolves to the sum of the two numbers
// and the current attempt.
async function activityFoo(a: number, b: number): Promise<number> {
  return a + b + activityInfo().attempt;
}

// Create a MockActivityEnvironment with attempt set to 2. Run the activityFoo
// function with parameters 5 and 35. Assert that the result is 42.
const env = new MockActivityEnvironment({ attempt: 2 });
const result = await env.run(activityFoo, 5, 35);
assert.equal(result, 42);
```

### Listen to Heartbeats {#listen-to-heartbeats}

When an Activity sends a Heartbeat, be sure that you can see the Heartbeats in your test code so that you can verify them.

[`MockActivityEnvironment`](https://typescript.temporal.io/api/classes/testing.MockActivityEnvironment) is an [`EventEmitter`](https://nodejs.org/api/events.html#class-eventemitter) that emits a `heartbeat` event that you can use to listen for Heartbeats emitted by the Activity.

When an Activity is run by a Worker, Heartbeats are throttled to avoid overloading the server.
`MockActivityEnvironment`, however, does not throttle Heartbeats.

```ts

async function activityFoo(): Promise<void> {
  heartbeat(6);
}

const env = new MockActivityEnvironment();

env.on('heartbeat', (d: unknown) => {
  assert(d === 6);
});

await env.run(activityFoo);
```

### Cancel an Activity {#cancel-an-activity}

If an Activity is supposed to react to a Cancellation, you can test whether it reacts correctly by canceling it.

[`MockActivityEnvironment`](https://typescript.temporal.io/api/classes/testing.MockActivityEnvironment) exposes a [`.cancel()`](https://typescript.temporal.io/api/classes/testing.MockActivityEnvironment#cancel) method that cancels the Activity Context.

```ts

async function activityFoo(): Promise<void> {
  heartbeat(6);
  // @temporalio/activity's sleep() is Cancellation-aware, which means that on Cancellation,
  // CancelledFailure will be thrown from it.
  await sleep(100);
}

const env = new MockActivityEnvironment();

env.on('heartbeat', (d: unknown) => {
  assert(d === 6);
});

await assert.rejects(env.run(activityFoo), (err) => {
  assert.ok(err instanceof CancelledFailure);
});
```

## Testing Workflows {#test-workflows}

### How to mock Activities {#mock-activities}

Mock the Activity invocation when unit testing your Workflows.

When integration testing Workflows with a Worker, you can mock Activities by providing mock Activity implementations to the Worker.

Implement only the relevant Activities for the Workflow being tested.

```ts

// Creating a mock object of the activities.
const mockActivities: Partial<typeof activities> = {
  makeHTTPRequest: async () => '99',
};

// Creating a worker with the mocked activities.
const worker = await Worker.create({
  activities: mockActivities,
  // ...
});
```

### How to skip time {#skip-time}

Some long-running Workflows can persist for months or even years.
Implementing the test framework allows your Workflow code to skip time and complete your tests in seconds rather than the Workflow's specified amount.

For example, if you have a Workflow sleep for a day, or have an Activity failure with a long retry interval, you don't need to wait the entire length of the sleep period to test whether the sleep function works.
Instead, test the logic that happens after the sleep by skipping forward in time and complete your tests in a timely manner.

The test framework included in most SDKs is an in-memory implementation of Temporal Server that supports skipping time.
Time is a global property of an instance of `TestWorkflowEnvironment`: skipping time (either automatically or manually) applies to all currently running tests.
If you need different time behaviors for different tests, run your tests in a series or with separate instances of the test server.
For example, you could run all tests with automatic time skipping in parallel, and then all tests with manual time skipping in series, and then all tests without time skipping in parallel.

#### Set up time skipping {#setting-up}

Set up the time-skipping test framework in the SDK of your choice.

```bash
npm install @temporalio/testing
```

The `@temporalio/testing` package downloads the test server and exports [`TestWorkflowEnvironment`](https://typescript.temporal.io/api/classes/testing.TestWorkflowEnvironment), which you use to connect the Client and Worker to the test server and interact with the test server.

[`TestWorkflowEnvironment.createTimeSkipping`](https://typescript.temporal.io/api/classes/testing.TestWorkflowEnvironment#createtimeskipping) starts the test server.
A typical test suite should set up a single instance of the test environment to be reused in all tests (for example, in a [Jest](https://jestjs.io/) `beforeAll` hook or a [Mocha](https://mochajs.org/) `before()` hook).

```typescript

let testEnv: TestWorkflowEnvironment;

// beforeAll and afterAll are injected by Jest
beforeAll(async () => {
  testEnv = await TestWorkflowEnvironment.createTimeSkipping();
});

afterAll(async () => {
  await testEnv?.teardown();
});
```

`TestWorkflowEnvironment` has [`client`](https://typescript.temporal.io/api/classes/testing.TestWorkflowEnvironment#client) and [`nativeConnection`](https://typescript.temporal.io/api/classes/testing.TestWorkflowEnvironment#nativeconnection) for creating Workers:

```typescript

test('workflowFoo', async () => {
  const worker = await Worker.create({
    connection: testEnv.nativeConnection,
    taskQueue: 'test',
    ...
  });
  const result = await worker.runUntil(
    testEnv.client.workflow.execute(workflowFoo, {
      workflowId: uuid4(),
      taskQueue: 'test',
    })
  );
  expect(result).toEqual('foo');
});
```

This test uses the test connection to create a Worker, runs the Worker until the Workflow is complete, and then makes an assertion about the Workflow's result.
The Workflow is executed using `testEnv.client.workflow`, which is connected to the test server.

#### Skip time automatically {#automatic-method}

You can skip time automatically in the SDK of your choice.
Start a test server process that skips time as needed.
For example, in the time-skipping mode, Timers, which include sleeps and conditional timeouts, are fast-forwarded except when Activities are running.

The test server starts in "normal" time.
When you use `TestWorkflowEnvironment.client.workflow.execute()` or `.result()`, the test server switches to "skipped" time mode until the Workflow completes.
In "skipped" mode, timers (`sleep()` calls and `condition()` timeouts) are fast-forwarded except when Activities are running.

`workflows.ts`

```ts

export async function sleeperWorkflow() {
  await sleep('1 day');
}
```

`test.ts`

```ts

test('sleep completes almost immediately', async () => {
  const worker = await Worker.create({
    connection: testEnv.nativeConnection,
    taskQueue: 'test',
    workflowsPath: require.resolve('./workflows'),
  });
  // Does not wait an entire day
  await worker.runUntil(
    testEnv.client.workflow.execute(sleeperWorkflow, {
      workflowId: uuid(),
      taskQueue: 'test',
    }),
  );
});
```

#### Skip time manually {#manual-method}

Skip time manually in the SDK of your choice.

You can call `testEnv.sleep()` from your test code to advance the test server's time.
This is useful for testing intermediate states or indefinitely long-running Workflows.
However, to use `testEnv.sleep()`, you need to avoid automatic time skipping by starting the Workflow with `.start()` instead of `.execute()` (and not calling `.result()`).

`workflow.ts`

```ts

export const daysQuery = defineQuery('days');

export async function sleeperWorkflow() {
  let numDays = 0;

  setHandler(daysQuery, () => numDays);

  for (let i = 0; i < 100; i++) {
    await sleep('1 day');
    numDays++;
  }
}
```

`test.ts`

```ts
test('sleeperWorkflow counts days correctly', async () => {
  const worker = await Worker.create({
    connection: testEnv.nativeConnection,
    taskQueue: 'test',
    workflowsPath: require.resolve('./workflows'),
  });

  // `start()` starts the test server in "normal" mode, not skipped time mode.
  // If you don't advance time using `testEnv.sleep()`, then `sleeperWorkflow()`
  // will run for days.
  handle = await testEnv.client.workflow.start(sleeperWorkflow, {
    workflowId: uuid4(),
    taskQueue,
  });

  worker.run();

  let numDays = await handle.query(daysQuery);
  assert.equal(numDays, 0);

  // Advance the test server's time by 25 hours
  await testEnv.sleep('25 hours');
  numDays = await handle.query(daysQuery);
  assert.equal(numDays, 1);

  await testEnv.sleep('25 hours');
  numDays = await handle.query(daysQuery);
  assert.equal(numDays, 2);
});
```

#### Skip time in Activities {#skip-time-in-activities}

Skip time in Activities in the SDK of your choice.

Call [`TestWorkflowEnvironment.sleep`](https://typescript.temporal.io/api/classes/testing.TestWorkflowEnvironment#sleep) from the mock Activity.

In the following test, `processOrderWorkflow` sends a notification to the user after one day.
The `processOrder` mocked Activity calls `testEnv.sleep(‘2 days')`, during which the Workflow sends email (by calling the `sendNotificationEmail` Activity).

Then, after the Workflow completes, we assert that `sendNotificationEmail` was called.

<details>
<summary>
Workflow implementation
</summary>

<!--SNIPSTART typescript-timer-reminder-workflow-->
[timer-examples/src/workflows.ts](https://github.com/temporalio/samples-typescript/blob/main/timer-examples/src/workflows.ts)
```ts
export async function processOrderWorkflow({
  orderProcessingMS,
  sendDelayedEmailTimeoutMS,
}: ProcessOrderOptions): Promise<string> {
  let processing = true;
  // Dynamically define the timeout based on given input
  const { processOrder } = proxyActivities<ReturnType<typeof createActivities>>({
    startToCloseTimeout: orderProcessingMS,
  });

  const processOrderPromise = processOrder().then(() => {
    processing = false;
  });

  await Promise.race([processOrderPromise, sleep(sendDelayedEmailTimeoutMS)]);

  if (processing) {
    await sendNotificationEmail();

    await processOrderPromise;
  }

  return 'Order completed!';
}
```
<!--SNIPEND-->

</details>

<!--SNIPSTART typescript-timer-reminder-test-->
[timer-examples/src/test/workflows.test.ts](https://github.com/temporalio/samples-typescript/blob/main/timer-examples/src/test/workflows.test.ts)
```ts
it('sends reminder email if processOrder does not complete in time', async () => {
  // This test doesn't actually take days to complete: the TestWorkflowEnvironment starts the
  // Test Server, which automatically skips time when there are no running Activities.
  let emailSent = false;
  const mockActivities: ReturnType<typeof createActivities> = {
    async processOrder() {
      // Test server switches to "normal" time while an Activity is executing.
      // Call `env.sleep` to skip ahead 2 days, by which time sendNotificationEmail
      // should have been called.
      await env.sleep('2 days');
    },
    async sendNotificationEmail() {
      emailSent = true;
    },
  };
  const worker = await Worker.create({
    connection: env.nativeConnection,
    taskQueue: 'test',
    workflowsPath: require.resolve('../workflows'),
    activities: mockActivities,
  });
  await worker.runUntil(
    env.client.workflow.execute(processOrderWorkflow, {
      workflowId: uuid(),
      taskQueue: 'test',
      args: [{ orderProcessingMS: ms('3 days'), sendDelayedEmailTimeoutMS: ms('1 day') }],
    }),
  );
  assert.ok(emailSent);
});
```
<!--SNIPEND-->

### Test functions in Workflow context {#workflow-context}

For a function or method to run in the Workflow context (where it's possible to get the current Workflow info, or running inside the sandbox in the case of TypeScript or Python), it needs to be run by the Worker as if it were a Workflow.

:::note

This section is applicable in Python and TypeScript.
In Python, we allow testing of Workflows only and not generic Workflow-related code.

:::

To test a function in your Workflow code that isn't a Workflow, put the file it's exported from in [WorkerOptions.workflowsPath](https://typescript.temporal.io/api/interfaces/worker.WorkerOptions#workflowspath).
Then execute the function as if it were a Workflow:

`workflows/file-with-workflow-function-to-test.ts`

```ts

export async function functionToTest(): Promise<number> {
  await sleep('1 day');
  return 42;
}
```

`test.ts`

```ts
const worker = await Worker.create({
  connection: testEnv.nativeConnection,
  workflowsPath: require.resolve(
    './workflows/file-with-workflow-function-to-test',
  ),
});

const result = await worker.runUntil(
  testEnv.client.workflow.execute(functionToTest, workflowOptions),
);

assert.equal(result, 42);
```

If `functionToTest` starts a Child Workflow, that Workflow must be exported from the same file (so that the Worker knows about it):

```ts

export { someWorkflowToRunAsChild };

export async function functionToTest(): Promise<number> {
  const result = await wf.executeChild(someWorkflowToRunAsChild);
  return result + 42;
}
```

### Assert in Workflow {#assert-in-workflow}

The `assert` statement is a convenient way to insert debugging assertions into the Workflow context.

The `assert` method is available in Python and TypeScript.

The Node.js [`assert`](https://nodejs.org/api/assert.html) module is included in Workflow bundles.

By default, a failed `assert` statement throws `AssertionError`, which causes a [Workflow Task](/tasks#workflow-task) to fail and be indefinitely retried.

To prevent this behavior, use [`workflowInterceptorModules`](https://typescript.temporal.io/api/namespaces/testing/#workflowinterceptormodules) from `@temporalio/testing`.
These interceptors catch an `AssertionError` and turn it into an `ApplicationFailure` that fails the entire Workflow Execution (not just the Workflow Task).

`workflows/file-with-workflow-function-to-test.ts`

```ts

export async function functionToTest() {
  assert.ok(false);
}
```

`test.ts`

```ts

  TestWorkflowEnvironment,
  workflowInterceptorModules,
} from '@temporalio/testing';

const worker = await Worker.create({
  connection: testEnv.nativeConnection,
  interceptors: {
    workflowModules: workflowInterceptorModules,
  },
  workflowsPath: require.resolve(
    './workflows/file-with-workflow-function-to-test',
  ),
});

await worker.runUntil(
  testEnv.client.workflow.execute(functionToTest, workflowOptions), // throws WorkflowFailedError
);
```

## How to Replay a Workflow Execution {#replay}

Replay recreates the exact state of a Workflow Execution.
You can replay a Workflow from the beginning of its Event History.

Replay succeeds only if the [Workflow Definition](/workflow-definition) is compatible with the provided history from a deterministic point of view.

When you test changes to your Workflow Definitions, we recommend doing the following as part of your CI checks:

1. Determine which Workflow Types or Task Queues (or both) will be targeted by the Worker code under test.
2. Download the Event Histories of a representative set of recent open and closed Workflows from each Task Queue, either programmatically using the SDK client or via the Temporal CLI.
3. Run the Event Histories through replay.
4. Fail CI if any error is encountered during replay.

The following are examples of fetching and replaying Event Histories:

To replay a single Event History, use [worker.runReplayHistory](https://typescript.temporal.io/api/classes/worker.Worker#runreplayhistory).

When an Event History is replayed and non-determinism is detected (that is, the Workflow code is incompatible with the History), [DeterminismViolationError](https://typescript.temporal.io/api/classes/workflow.DeterminismViolationError) is thrown.
If replay fails for any other reason, [ReplayError](https://typescript.temporal.io/api/classes/worker.ReplayError) is thrown.

In the following example, a single Event History is loaded from a JSON file on disk (as obtained from the [Web UI](/web-ui) or the [Temporal CLI](/cli/workflow#show)):

```ts
const filePath = './history_file.json';
const history = await JSON.parse(fs.promises.readFile(filePath, 'utf8'));
await Worker.runReplayHistory(
  {
    workflowsPath: require.resolve('./your/workflows'),
  },
  history,
);
```

Alternatively, we can download the Event History programmatically using a Client:

```ts
const connection = await Connection.connect({ address });
const client = new Client({ connection, namespace: 'your-namespace' });
const handle = client.workflow.getHandle('your-workflow-id');
const history = await handle.fetchHistory();
await Worker.runReplayHistory(
  {
    workflowsPath: require.resolve('./your/workflows'),
  },
  history,
);
```

To gain confidence that changes to a Workflow are safe to deploy, we recommend that you obtain Event Histories from the relevant Task Queue and replay them in bulk.
You can do so by combining the [Client.workflow.list()](https://typescript.temporal.io/api/classes/client.WorkflowClient#list) and [worker.runReplayHistories()](https://typescript.temporal.io/api/classes/worker.Worker#runreplayhistories) APIs.

In the following example (which, as of server 1.18, requires [Advanced Visibility](/visibility#advanced-visibility) to be enabled), Event Histories are downloaded from the server and then replayed by passing in a client and a set of Workflows Executions.
The [results](https://typescript.temporal.io/api/interfaces/worker.ReplayResult) returned by the async iterator contain information about the Workflow Execution and whether an error occurred during replay.

```ts
const executions = client.workflow.list({
  query: 'TaskQueue=foo and StartTime > "2022-01-01T12:00:00"',
});
const histories = executions.intoHistories();
const results = Worker.runReplayHistories(
  {
    workflowsPath: require.resolve('./your/workflows'),
  },
  histories,
);
for await (const result of results) {
  if (result.error) {
    console.error('Replay failed', result);
  }
}
```

---

## Durable Timers - TypeScript SDK

## What is a Timer? {#timers}

A Workflow can set a durable Timer for a fixed time period.
In some SDKs, the function is called `sleep()`, and in others, it's called `timer()`.

A Workflow can sleep for months.
Timers are persisted, so even if your Worker or Temporal Service is down when the time period completes, as soon as your Worker and Temporal Service are back up, the `sleep()` call will resolve and your code will continue executing.

Sleeping is a resource-light operation: it does not tie up the process, and you can run millions of Timers off a single Worker.

## Asynchronous design patterns in TypeScript {#asynchronous-design-patterns}

The real value of `sleep` and `condition` is in knowing how to use them to model asynchronous business logic.
Here are some examples we use the most; we welcome more if you can think of them!

<details>
<summary>
Racing Timers
</summary>

Use `Promise.race` with Timers to dynamically adjust delays.

```ts
export async function processOrderWorkflow({
  orderProcessingMS,
  sendDelayedEmailTimeoutMS,
}: ProcessOrderOptions): Promise<void> {
  let processing = true;
  const processOrderPromise = processOrder(orderProcessingMS).then(() => {
    processing = false;
  });

  await Promise.race([processOrderPromise, sleep(sendDelayedEmailTimeoutMS)]);

  if (processing) {
    await sendNotificationEmail();
    await processOrderPromise;
  }
}
```

</details>
<details>
<summary>
Racing Signals
</summary>

Use `Promise.race` with Signals and Triggers to have a promise resolve at the earlier of either system time or human intervention.

```ts

const userInteraction = new Trigger<boolean>();
const completeUserInteraction = defineSignal('completeUserInteraction');

export async function yourWorkflow(userId: string) {
  setHandler(completeUserInteraction, () => userInteraction.resolve(true)); // programmatic resolve
  const userInteracted = await Promise.race([
    userInteraction,
    sleep('30 days'),
  ]);
  if (!userInteracted) {
    await sendReminderEmail(userId);
  }
}
```

You can invert this to create a reminder pattern where the promise resolves _if_ no Signal is received.

:::caution Antipattern: Racing sleep.then

Be careful when racing a chained `sleep`.
This might cause bugs because the chained `.then` will still continue to execute.

```ts
await Promise.race([
  sleep('5s').then(() => (status = 'timed_out')),
  somethingElse.then(() => (status = 'processed')),
]);

if (status === 'processed') await complete(); // takes more than 5 seconds
// status = timed_out
```

:::

</details>

<details>
<summary>
Updatable Timer
</summary>

Here is how you can build an updatable Timer with `condition`:

```ts

// usage
export async function countdownWorkflow(): Promise<void> {
  const target = Date.now() + 24 * 60 * 60 * 1000; // 1 day!!!
  const timer = new UpdatableTimer(target);
  console.log('timer set for: ' + new Date(target).toString());
  wf.setHandler(setDeadlineSignal, (deadline) => {
    // send in new deadlines via Signal
    timer.deadline = deadline;
    console.log('timer now set for: ' + new Date(deadline).toString());
  });
  wf.setHandler(timeLeftQuery, () => timer.deadline - Date.now());
  await timer; // if you send in a signal with a new time, this timer will resolve earlier!
  console.log('countdown done!');
}
```

This is available in the third-party package [`temporal-time-utils`](https://www.npmjs.com/package/temporal-time-utils#user-content-updatabletimer), where you can also see the implementation:

```ts
// implementation
export class UpdatableTimer implements PromiseLike<void> {
  deadlineUpdated = false;
  #deadline: number;

  constructor(deadline: number) {
    this.#deadline = deadline;
  }

  private async run(): Promise<void> {
    /* eslint-disable no-constant-condition */
    while (true) {
      this.deadlineUpdated = false;
      if (
        !(await wf.condition(
          () => this.deadlineUpdated,
          this.#deadline - Date.now(),
        ))
      ) {
        break;
      }
    }
  }

  then<TResult1 = void, TResult2 = never>(
    onfulfilled?: (value: void) => TResult1 | PromiseLike<TResult1>,
    onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2>,
  ): PromiseLike<TResult1 | TResult2> {
    return this.run().then(onfulfilled, onrejected);
  }

  set deadline(value: number) {
    this.#deadline = value;
    this.deadlineUpdated = true;
  }

  get deadline(): number {
    return this.#deadline;
  }
}
```

</details>

---

## Versioning - TypeScript SDK

Since Workflow Executions in Temporal can run for long periods — sometimes months or even years — it's common to need to make changes to a Workflow Definition, even while a particular Workflow Execution is in progress.

The Temporal Platform requires that Workflow code is [deterministic](/workflow-definition#deterministic-constraints).
If you make a change to your Workflow code that would cause non-deterministic behavior on Replay, you'll need to use one of our Versioning methods to gracefully update your running Workflows.
With Versioning, you can modify your Workflow Definition so that new executions use the updated code, while existing ones continue running the original version.
There are two primary Versioning methods that you can use:

- [Worker Versioning](/production-deployment/worker-deployments/worker-versioning). The Worker Versioning feature allows you to tag your Workers and programmatically roll them out in versioned deployments, so that old Workers can run old code paths and new Workers can run new code paths.
- [Versioning with Patching](#patching). This method works by adding branches to your code tied to specific revisions. It applies a code change to new Workflow Executions while avoiding disruptive changes to in-progress Workflow Executions.

:::danger
Support for the experimental Worker Versioning method before 2025 will be removed from Temporal Server in March 2026. Refer to the [latest Worker Versioning docs](/worker-versioning) for guidance. You can still refer to the [Worker Versioning Legacy](worker-versioning-legacy) docs if needed. 
:::

## Versioning with Patching {#patching}

### Adding a patch

A Patch defines a logical branch in a Workflow for a specific change, similar to a feature flag.
It applies a code change to new Workflow Executions while avoiding disruptive changes to in-progress Workflow Executions.
When you want to make substantive code changes that may affect existing Workflow Executions, create a patch. Note that there's no need to patch [Pinned Workflows](/worker-versioning).

Suppose you have an initial Workflow that runs `activityA`:

```ts
// v1
export async function myWorkflow(): Promise<void> {
  await activityA();
  await sleep('1 days'); // arbitrary long sleep to simulate a long running workflow we need to patch
  await activityThatMustRunAfterA();
}
```

Now, you want to update your code to run `activityB` instead. This represents your desired end state.

```ts
// vFinal
export async function myWorkflow(): Promise<void> {
  await activityB();
  await sleep('1 days');
}
```

The problem is that you cannot deploy this `vFinal` revision directly until you're certain there are no more running Workflows created using the `v1` code, otherwise you are likely to cause a nondeterminism error.
Instead, you'll need to use the [`patched`](https://typescript.temporal.io/api/namespaces/workflow#patched) function to check which version of the code should be executed.

Patching is a three-step process:

1. Patch in any new, updated code using the `patched()` function. Run the new patched code alongside old code.
2. Remove old code and use `deprecatePatch()` to mark a particular patch as deprecated.
3. Once there are no longer any open Worklow Executions of the previous version of the code, remove `deprecatePatch()`.
   Let's walk through this process in sequence.

### Patching in new code

Using `patched` inserts a marker into the Workflow History.
During Replay, if a Worker encounters a history with that marker, it will fail the Workflow task when the Workflow code doesn't produce the same patch marker (in this case `your-change-id`).
This ensures you can safely deploy code from `v2` as a "feature flag" alongside the original version (`v1`).

```ts
// v2

export async function myWorkflow(): Promise<void> {
  if (patched('my-change-id')) {
    await activityB();
    await sleep('1 days');
  } else {
    await activityA();
    await sleep('1 days');
    await activityThatMustRunAfterA();
  }
}
```

### Deprecating patches {#deprecated-patches}

After ensuring that all Workflows started with `v1` code have left retention, you can [deprecate the patch](https://typescript.temporal.io/api/namespaces/workflow#deprecatepatch).

Once your Workflows are no longer running the pre-patch code paths, you can deploy your code with `deprecatePatch()`.
These Workers will be running the most up-to-date version of the Workflow code, which no longer requires the patch.
Deprecated patches serve as a bridge between the final stage of the patching process and the final state that no longer has patches. They function similarly to regular patches by adding a marker to the Workflow History. However, this marker won't cause a replay failure when the Workflow code doesn't produce it.

```ts
// v3

export async function myWorkflow(): Promise<void> {
  deprecatePatch('my-change-id');
  await activityB();
  await sleep('1 days');
}
```

### Removing a patch {#deploy-new-code}

Once your pre-patch Workflows have left retention, you can then safely deploy Workers that no longer use either the `patched()` or `deprecatePatch()` calls:

Patching allows you to make changes to currently running Workflows.
It is a powerful method for introducing compatible changes without introducing non-determinism errors.

### Workflow cutovers

To understand why Patching is useful, it's helpful to demonstrate cutting over an entire Workflow.

Since incompatible changes only affect open Workflow Executions of the same type, you can avoid determinism errors by creating a whole new Workflow when making changes.
To do this, you can copy the Workflow Definition function, giving it a different name, and register both names with your Workers.

For example, you would duplicate `PizzaWorkflow` as `PizzaWorkflowV2`:

```typescript
function pizzaWorkflow(order: PizzaOrder): Promise<OrderConfirmation> {
  // this function contains the original code
}

function pizzaWorkflowV2(order: PizzaOrder): Promise<OrderConfirmation> {
  // this function contains the updated code
}
```

You would then need to update the Worker configuration, and any other identifier strings, to register both Workflow Types:

```typescript
const worker = await Worker.create({
  workflowsPath: require.resolve('./workflows'),
  // other configurations
});
```

The downside of this method is that it requires you to duplicate code and to update any commands used to start the Workflow.
This can become impractical over time.
This method also does not provide a way to version any still-running Workflows -- it is essentially just a cutover, unlike Patching.

### Testing a Workflow for replay safety

To determine whether your Workflow your needs a patch, or that you've patched it successfully, you should incorporate [Replay Testing](/develop/typescript/testing-suite#replay).

## Worker Versioning

Temporal's [Worker Versioning](/production-deployment/worker-deployments/worker-versioning) feature allows you to tag your Workers and programmatically roll them out in Deployment Versions, so that old Workers can run old code paths and new Workers can run new code paths. This way, you can pin your Workflows to specific revisions, avoiding the need for patching.

---

## Worker Versioning (Legacy) - Typescript SDK

## How to use Worker Versioning in TypeScript (Deprecated) {#worker-versioning}

:::caution

This section is for a deprecated Worker Versioning API. Please redirect your attention to [Worker Versioning](/production-deployment/worker-deployments/worker-versioning).

See the [Pre-release README](https://github.com/temporalio/temporal/blob/main/docs/worker-versioning.md) for more information.

:::

A Build ID corresponds to a deployment. If you don't already have one, we recommend a hash of the code--such as a Git SHA--combined with a human-readable timestamp.
To use Worker Versioning, you need to pass a Build ID to your Typescript Worker and opt in to Worker Versioning.

### Assign a Build ID to your Worker and opt in to Worker Versioning

You should understand assignment rules before completing this step.
See the [Worker Versioning Pre-release README](https://github.com/temporalio/temporal/blob/main/docs/worker-versioning.md) for more information.

To enable Worker Versioning for your Worker, assign the Build ID--perhaps from an environment variable--and turn it on.

```typescript
// ...
const worker = await Worker.create({
  taskQueue: 'your_task_queue_name',
  buildId: buildId,
  useVersioning: true,
  // ...
});
// ...
```

:::warning

Importantly, when you start this Worker, it won't receive any tasks until you set up assignment rules.

:::

### Specify versions for Activities, Child Workflows, and Continue-as-New Workflows

:::caution

This section is for a deprecated Worker Versioning API. Please redirect your attention to [Worker Versioning](/production-deployment/worker-deployments/worker-versioning).

:::

By default, Activities, Child Workflows, and Continue-as-New Workflows are run on the build of the Workflow that created them if they are also configured to run on the same Task Queue.
When configured to run on a separate task queue, they will default to using the current assignment rules.

If you want to override this behavior, you can specify your intent via the `versioningIntent`
field available on the options object for each of these commands.

For example, if you want an Activity to use the latest assignment rules rather than inheriting from its parent:

```typescript
// ...
const { echo } = proxyActivities<typeof activities>({
  startToCloseTimeout: '20s',
  versioningIntent: 'USE_ASSIGNMENT_RULES',
});
// ...
```

### Tell the Task Queue about your Worker's Build ID (Deprecated)

:::caution

This section is for a deprecated Worker Versioning API. Please redirect your attention to [Worker Versioning](/production-deployment/worker-deployments/worker-versioning).

:::

Now you can use the SDK (or the Temporal CLI) to tell the Task Queue about your Worker's Build ID.
You might want to do this as part of your CI deployment process.

```typescript
// ...
await client.taskQueue.updateBuildIdCompatibility('your_task_queue_name', {
  operation: 'addNewIdInNewDefaultSet',
  buildId: 'deadbeef',
});
```

This code adds the `deadbeef` Build ID to the Task Queue as the sole version in a new version set, which becomes the default for the queue.
New Workflows execute on Workers with this Build ID, and existing ones will continue to process by appropriately compatible Workers.

If, instead, you want to add the Build ID to an existing compatible set, you can do this:

```typescript
// ...
await client.taskQueue.updateBuildIdCompatibility('your_task_queue_name', {
  operation: 'addNewCompatibleVersion',
  buildId: 'deadbeef',
  existingCompatibleBuildId: 'some-existing-build-id',
});
```

This code adds `deadbeef` to the existing compatible set containing `some-existing-build-id` and marks it as the new default Build ID for that set.

You can promote an existing Build ID in a set to be the default for that set:

```typescript
// ...
await client.taskQueue.updateBuildIdCompatibility('your_task_queue_name', {
  operation: 'promoteBuildIdWithinSet',
  buildId: 'deadbeef',
});
```

You can promote an entire set to become the default set for the queue. New Workflows will start using that set's default build.

```typescript
// ...
await client.taskQueue.updateBuildIdCompatibility('your_task_queue_name', {
  operation: 'promoteSetByBuildId',
  buildId: 'deadbeef',
});
```

You can merge two sets into one, preserving the primary set's default Build ID as the default
for the merged set.

```typescript
// ...
await client.taskQueue.updateBuildIdCompatibility('your_task_queue_name', {
  operation: 'mergeSets',
  primaryBuildId: 'deadbeef',
  secondaryBuildId: 'some-existing-build-id',
});
```

---

## Worker performance

This page documents metrics and configurations that drive the efficiency of your Worker fleet.
It provides coverage of performance metric families, Worker configuration options, Task Queue information, backlog counts, Task rates, and how to evaluate Worker availability.
This content covers practical methods for querying Task Queue information, and strategies for tuning Workers and Task Queue processing so you manage your resources effectively.

:::info

All metrics on this page are prepended with the `temporal_` prefix.
For example, `worker_task_slots_available` is actually `temporal_worker_task_slots_available` when used.
The omitted prefix makes the names more readable and descriptive.

:::

## Worker performance concepts {#worker-performance-concepts}

A Worker's performance characteristics are affected by, but not limited to, the following elements.

### Task slots {#slots}

A **Worker Task Slot**, represents the capacity of a Temporal Worker to execute a single concurrent Task.
Slots are crucial for managing the workload and performance of Workers in a Temporal application.
They're used for both Workflow and Activity Tasks.
When a Worker starts processing a Task, it occupies one slot.
The number of available slots directly affects how many tasks a Worker can handle simultaneously.

### Slot suppliers {#slot-suppliers}

A **Slot Supplier** defines a strategy to provide slots for a Worker, increasing or decreasing the Worker's slot count.
The supplier determines when it's acceptable to begin a new Task.
Each supplier manages one slot type.
There are slot types for Activity, Workflow, Nexus, or Local Activity Tasks.
An available slot determines whether or not a Worker is willing to poll for, and execute, a new Task of that type.

Slot supplier strategies include manual assignment of fixed slot counts and resource-balanced "auto-tuner" assignment.
Resource-based suppliers adjust slot counts based on CPU and memory resources.
Available slot suppliers include:

- **Fixed Size Slot Suppliers**:
  Hands out slots up to a preset limit.
  This is useful if you have a concrete idea of how many resources your tasks are going to consume, and can easily determine an upper bound on how many should run at once.
  When you need the absolute best performance, review your hardware and environment characteristics.
  This information lets you calculate an appropriate fixed-size limit.
  Evaluate the maximum number of slots you can support without oversubscribing or hitting out-of-memory conditions ("OOMing").
  Using that value with a fixed-size supplier provides optimal results with the least overhead.

- **Resource-Based Slot Suppliers**:
  Hands out slots based on real-time CPU and memory usage.
  You set target utilization for both CPU and memory and the Slot Supplier tries to reach those values without exceeding them under load.
  A resource-based supplier will account for memory limits imposed in containerized environments.
  It dynamically adjusts the number of available slots for different task types with respect to current system resources.

- **Custom Slot Suppliers**:
  Hands out slots based on the custom logic that you define.
  Use this approach when you need complete control over when Workers accept and execute Tasks.
  For implementation details, see [Implement Custom Slot Suppliers](#custom-slot-implementation).

:::caution

- You cannot guarantee that the targets for resource-based suppliers won't ever be exceeded.
  Resources consumed during a task can't be known ahead of time.

- Worker tuners supersede the existing `maxConcurrentXXXTask` style Worker options.
  Using both styles will cause an error at Worker initialization time.

:::

### Worker tuning {#worker-tuning}

Worker tuning is the process of defining customized slot suppliers for the different task slots of a Worker to fine-tune its performance.
You use special types called **Worker tuners** that assign slot suppliers to various Task Types, including Worker, Activity, Nexus, and Local Activity Tasks.

For more on how to configure and use Worker tuners, refer to [Worker runtime performance tuning](#worker-performance-tuning).

:::caution

Worker tuners supersede the existing `maxConcurrentXXXTask` style Worker options.
  Using both styles will cause an error at Worker initialization time.

:::

### Task Pollers 

A Worker's **Task Pollers** play a crucial role in the Temporal architecture by efficiently ingesting work to Workers to support scalable, resilient Workflow Execution. 
Pollers create long-polling connections to the Temporal Service and actively poll a Task Queue for Tasks to process. When a Task Poller receives a Task, it delivers the Task to the appropriate Executor Slot for processing.

Temporal SDKs implement support for *Poller Autoscaling*, which dynamically adjusts the number of pollers in use to maximize throughput for a given number of workers and the size of the task backlog. 
Temporal recommends using Poller Autoscaling for the majority of use cases, as manually setting the number of pollers too high or too low for your workload will result in decreased performance. 
To configure Poller Autoscaling, see [Configuring Poller Options](#configuring-poller-options) and samples for each Temporal SDK.

### Eager task execution

:::caution
Eager start does not respect Worker versioning. An eagerly started Workflow may run on any available local Worker even if that Worker is not the Current or Ramping version of its Worker deployment.
:::

As a latency optimization, Activity and Workflow Tasks may be started eagerly in a local Worker under the right circumstances.

#### Eager Activity Start

Eager Activity Start may happen automatically if the Worker processing a Workflow Task has also registered the Activity Definition being called.
If it does, it may try to reserve an Activity Slot for the execution of the Activity, and the server may respond to the Workflow Task completion with the Activity Task for the worker to execute immediately.

#### Eager Workflow Start

:::tip SUPPORT, STABILITY, and DEPENDENCY INFO

Eager Workflow Start is available in [Public Preview](/evaluate/development-production-features/release-stages#public-preview) in the Go, Java, Python, and .NET SDKs.
Temporal Cloud and Temporal Server 1.29.0 and higher have Eager Workflow Start available for use by default, but you must explicitly Request-Eager-Start when starting a Workflow.

:::

Eager Workflow Start reduces the latency required to initiate a Workflow execution.
It is recommended for short-lived Workflows that use Local Activities to interact with external services, especially when these interactions are initiated in the first Workflow Task and the Workflow is deployed near the Temporal Server to minimize network delay.

This feature is particularly beneficial for Workflows with a “happy path” that must begin external interactions within tens of milliseconds, while still relying on Temporal’s server-driven retries and compensation mechanisms to ensure reliability in failure scenarios.

**Quick Start**

Eager Workflow Start requires the Starter and the Worker to share a Client located in the same process and setting the `request_eager_start` (or similar name) to true in the Start Workflow call.
When set, and the Worker has a Workflow Task slot available and the Workflow Definition registered, the Worker can execute the first task of the Workflow locally without first making a round-trip to the Temporal Server.
This is typically most useful in combination with a Local Activity executing in the first Workflow Task, since other Workflow API calls that require waiting on something will force a round-trip.

:::tip RESOURCES

- [Go SDK - Code sample](https://github.com/temporalio/samples-go/tree/main/eager-workflow-start)
- [Java SDK - Code sample](https://github.com/temporalio/samples-java/blob/main/core/src/main/java/io/temporal/samples/hello/HelloEagerWorkflowStart.java)
- Python SDK - use `request_eager_start` when calling `start_workflow` or `execute_workflow`
- .NET SDK - use `RequestEagerStart` in your `WorkflowOptions` when starting a workflow
- [Blog: Improving Latency with Eager Workflow Start](https://temporal.io/blog/improving-latency-with-eager-workflow-start)

:::

**How it works**

The traditional way to start a Workflow decouples the starter program from the worker by sharing a Task Queue name between them, similar to a publish/subscribe pattern.
This has many advantages: for example, we can reliably schedule a Workflow Execution without a running Worker, or separate the Worker and Workflow implementation from the Starter application and host them independently.

But decoupling also makes it harder to optimize for latency.
Instead, when the **Starter and Worker are collocated in the same process** and aware of each other, they can interact while bypassing the server, saving a few time-intensive operations.

<CaptionedImage
    src="/img/develop/worker-performance/eager-workflow-start-flow.png"
    title="Eager Workflow Start"
/>

The above figure shows Eager Workflow Start in action:

1. The process begins with the Starter setting `request_eager_start` (or similar name) to true in the Start Workflow Options.
1. The SDK will try to locate a local Worker that is willing to execute the first Workflow Task, and reserve an execution slot for it.
1. If successful, the SDK will provide a hint to the server that eager mode is preferred for the new Workflow.
1. The server not only registers the start of the Workflow in history, it also assigns the first Workflow Task to the Starter, all in the same DB update.
1. The first task is included in the server response, no matching step required.
1. The SDK extracts the task from the response, and dispatches it to the local worker.

To recover from errors, Eager Workflow Start falls back to the non-eager path. For example, when the first Task is returned eagerly, but the local Worker fails or times out while processing the task, the server retries this task non-eagerly after WorkflowTaskTimeout.

## Performance metrics for tuning {#metrics}

The Temporal SDKs emit metrics from Temporal Client usage and Worker Processes.
Performance tuning uses three important SDK metric groups:

### Slot availability metrics

Temporal's [`worker_task_slots_available`](/references/sdk-metrics#worker_task_slots_available) and `worker_task_slots_used` gauges can report the number of available executor “slots” that are currently available and unoccupied for a Worker type.
Tag these with `worker_type=WorkflowWorker` for Workflow Task Workers or `worker_type=ActivityWorker` for Activity Workers.

:::tip

Unlike `worker_task_slots_used`, `worker_task_slots_available` can only be used with fixed size slot suppliers and can't be used with resource-based slot suppliers.

:::

### Latency metrics

Temporal provides two latency timers: [`workflow_task_schedule_to_start_latency`](/references/sdk-metrics#workflow_task_schedule_to_start_latency) for Workflow Tasks and [`activity_schedule_to_start_latency`](/references/sdk-metrics#activity_schedule_to_start_latency) for Activities.
A Schedule-To-Start latency is the time from when an Task is scheduled (that is, placed in a Queue) to when a Worker starts (that is, picks up from the Task Queue) that Task.
These metrics help ensure that Tasks are being processed from the queue in a timely manner.
For more information about `schedule_to_start` timeout and latency, see [Schedule-To-Start Timeout](/encyclopedia/detecting-activity-failures#schedule-to-start-timeout).

### Cache metrics

The [`sticky_cache_size`](/references/sdk-metrics#sticky_cache_size) and [`workflow_active_thread_count`](/references/sdk-metrics#workflow_active_thread_count) metrics report the size of the Workflow cache and the number of cached Workflow threads.

## Worker performance options {#configuration}

Each Worker can be configured by providing custom Worker options (`WorkerOptions`) at instantiation.
Options are specific to individual Workers and do not affect other members of your fleet.

### Executor slot options

The `maxConcurrentWorkflowTaskExecutionSize` and `maxConcurrentActivityExecutionSize` options define the number of total available Workflow Task and Activity Task slots for a Worker.

:::caution

- Worker tuners supersede the existing `maxConcurrentXXXTask` style Worker options.
  Using both styles will cause an error at Worker initialization time.

:::

### Configuring Poller Options 

#### Recommended Approach

The Temporal SDKs support Poller Autoscaling, which automatically selects an appropriate number of pollers based on need. Using this feature results in more efficient poller usage, better throughput, and schedule-to-start latency improvements. You can enable this feature by setting the `*_task_poller_behavior` options to `PollerBehaviorAutoscaling`. Names may vary slightly depending on the SDK. For specific examples of enabling Poller Autoscaling, see the SDK Examples section below. Poller Autoscaling will be the default configuration in future versions of Temporal SDKs. 

#### Manual Configuration

There are options available to manually configure minimum, maximum, and initial poller counts, but it is not recommended to set these values manually for production use cases. To set these values manually, the following options are available: 

- `maxConcurrentWorkflowTaskPollers` (in the JavaSDK: `workflowPollThreadCount`)
- `maxConcurrentActivityTaskPollers` (in the JavaSDK: `activityPollThreadCount`)

These options define the maximum count of pollers performing poll requests on Workflow and Activity Task Queues, respectively. 

#### SDK Examples

<SdkTabs>
<SdkTabs.Go>
[Go SDK docs](https://pkg.go.dev/go.temporal.io/sdk/worker#PollerBehaviorAutoscalingOptions)
```go
w := worker.New(c, "my-task-queue", worker.Options{
  WorkflowTaskPollerBehavior: worker.NewPollerBehaviorAutoscaling(worker.PollerBehaviorAutoscalingOptions{}),
  ActivityTaskPollerBehavior: worker.NewPollerBehaviorAutoscaling(worker.PollerBehaviorAutoscalingOptions{}),
  NexusTaskPollerBehavior: worker.NewPollerBehaviorAutoscaling(worker.PollerBehaviorAutoscalingOptions{}),
})
```
</SdkTabs.Go>
<SdkTabs.Java>
[Java SDK docs](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/worker/tuning/PollerBehaviorAutoscaling.html)
```java
public class WorkerExample {
    public static void main(String[] args) {
        WorkflowServiceStubs service = WorkflowServiceStubs.newLocalServiceStubs();
        WorkflowClient client = WorkflowClient.newInstance(service);
        WorkerFactory factory = WorkerFactory.newInstance(client);
        WorkerOptions workerOptions = WorkerOptions.newBuilder()
            .setWorkflowTaskPollersBehavior(new PollerBehaviorAutoscaling())
            .setActivityTaskPollersBehavior(new PollerBehaviorAutoscaling())
            .setNexusTaskPollersBehavior(new PollerBehaviorAutoscaling())
            .build();

        Worker worker = factory.newWorker("my-task-queue", workerOptions);
    }
}
```
</SdkTabs.Java>
<SdkTabs.Python>
[Python SDK docs](https://python.temporal.io/temporalio.worker.PollerBehaviorAutoscaling.html)
```python
worker = Worker(
    client,
    task_queue="my-task-queue",
    workflows=[MyWorkflow],
    activities=[my_activity],
    
    workflow_task_poller_behavior=PollerBehaviorAutoscaling(),
    activity_task_poller_behavior=PollerBehaviorAutoscaling(),
    nexus_task_poller_behavior=PollerBehaviorAutoscaling(),
)
```
</SdkTabs.Python>
<SdkTabs.TypeScript>
[TypeScript SDK docs](https://typescript.temporal.io/api/interfaces/proto.temporal.api.sdk.v1.WorkerConfig.IAutoscalingPollerBehavior)
```ts
const worker = await Worker.create({
  connection,
  taskQueue: 'my-task-queue',
  workflowsPath: require.resolve('./workflows'),
  activities,
  
  workflowTaskPollerBehavior: PollerBehavior.autoscaling(),
  activityTaskPollerBehavior: PollerBehavior.autoscaling(),
  nexusTaskPollerBehavior: PollerBehavior.autoscaling(),
});
```
</SdkTabs.TypeScript>
<SdkTabs.DotNet>
[DotNet SDK docs](https://dotnet.temporal.io/api/Temporalio.Worker.Tuning.PollerBehavior.Autoscaling.html)
```csharp
using var worker = new TemporalWorker(
    client,
    new TemporalWorkerOptions("my-task-queue")
    {
        WorkflowTaskPollerBehavior = new PollerBehavior.Autoscaling(),
        ActivityTaskPollerBehavior = new PollerBehavior.Autoscaling(),
        NexusTaskPollerBehavior = new PollerBehavior.Autoscaling(),
    }
    .AddWorkflow<MyWorkflow>()
    .AddActivity(MyActivities.MyActivity)
);
```
</SdkTabs.DotNet>
<SdkTabs.Ruby>
[Ruby SDK docs](https://ruby.temporal.io/Temporalio/Worker/PollerBehavior/Autoscaling.html)
```ruby
worker = Temporalio::Worker.new(
  client,
  'my-task-queue',
  workflows: [MyWorkflow],
  activities: [MyActivity],
  
  workflow_task_poller_behavior: Temporalio::Worker::PollerBehaviorAutoscaling.new,
  activity_task_poller_behavior: Temporalio::Worker::PollerBehaviorAutoscaling.new,
  nexus_task_poller_behavior: Temporalio::Worker::PollerBehaviorAutoscaling.new,
)

```

</SdkTabs.Ruby>
</SdkTabs>

### Cache options

A Workflow Cache is created and shared between all Workers on a single host.
It's designed to limit the resources used by the cache for each host/process.
These options are defined on `WorkerFactoryOptions` in JavaSDK and in `worker` package in GoSDK:

- `worker.setStickyWorkflowCacheSize` (JavaSDK: `WorkerFactoryOptions#workflowCacheSize`) defines the maximum number of cached Workflows Executions.
  Each cached Workflow contains at least one Workflow thread and its resources.
  Resources include memory, etc.
- `maxWorkflowThreadCount` defines the maximum number of Workflow threads that may exist concurrently at any time.

These cache options limit the resource consumption of the in-memory Workflow cache.
Workflow cache options are shared between all Workers because the Workflow cache is tightly integrated with the resource consumption of the entire host.
This includes memory and the total thread count, which should be limited per host/JVM.

### "Large value" drawbacks

There are drawbacks when you use "large values everywhere."
As with any multithreading system, specifying excessively large values without monitoring with the SDK and system metrics leads to constant resource contention/stealing
This decreases the total throughput and increases latency jitter of the system.

### Invariants (JavaSDK only) {#invariants}

These properties should always be true for a Worker's configuration.

Perform this sanity check after the adjustments to Worker settings.

1. `workflowCacheSize` should be ≤ `maxWorkflowThreadCount`. Each Workflow has at least one Workflow thread.
2. `maxConcurrentWorkflowTaskExecutionSize` should be ≤ `maxWorkflowThreadCount`. Having more Worker slots than the Workflow cache size will lead to resource contention/stealing between executors and unpredictable delays. It's recommended that `maxWorkflowThreadCount` be at least 2x of `maxConcurrentWorkflowTaskExecutionSize`.
3. `maxConcurrentWorkflowTaskPollers` should be significantly ≤ `maxConcurrentWorkflowTaskExecutionSize`. And `maxConcurrentActivityTaskPollers` should be significantly ≤ `maxConcurrentActivityExecutionSize`. The number of pollers should always be lower than the number of executors.

## Worker runtime performance tuning {#worker-performance-tuning}

Worker tuning manages the assignment of slot suppliers.
A **Worker Tuner** instance exists per-Worker, providing slot suppliers for different slot types (Activity, Workflow, Nexus, or Local Activity Tasks).
A tuner assigns different suppliers to each slot type.
For example, it might provide a fixed assignment slot supplier for Workflows and use a resource-based supplier for Activities.

### Choosing slot supplier types

Temporal offers three types of slot suppliers: fixed assignment, resource-based, and custom.
Here’s how to choose the best approach based on your system requirements and workload characteristics.

When choosing whether to opt for fixed assignment or resource-based suppliers, consider:

- Workflow Tasks make minimal demands on the CPU and, normally, do not consume much memory.
  They are well-served by fixed-sized slot suppliers.
- When very low Task completion latency is a concern, avoid resourced-based auto-tuning slot suppliers.
- Reserve auto-tuned resource-based slot suppliers for deployments focused on avoiding Worker overload.
  They provide excellent balance with built-in throttling that ensures the Worker will be cautious when handing out new executor slots.

The following use cases are particularly well suited to resource-based auto-tuning slot suppliers:

- **Fluctuating workloads with low per-Task consumption**:
  The resource-based supplier works well when each Task consumes few resources but may run for a (relatively) long time.
  For example: HTTP calls or other blocking I/Os that spend most of their time waiting on external events.
- **Protection from out-of-memory & over-subscription in the face of unpredictable per-task consumption:**
  Do your Tasks often consume an unpredictable number of resources?
  Do you want to avoid crashes without setting an overly-conservative fixed limit?
  In these cases, the resource-based supplier is a good match.
  Keep in mind that auto-tuning can never do a _perfect_ job and may sometimes exceed your requested system limits for CPU and memory.

For the highest level of control over slot allocation, consider custom slot suppliers.
This allows you to tailor the logic of how slots are allocated based on your system requirements.
Custom suppliers provide flexibility to optimize for specific use cases that fixed assignment and resource-based suppliers may not fully address.

Choosing the right slot supplier depends on your workload complexity and the control you need over resource allocation.
For predictable tasks, variable workloads, or complex dynamic scenarios, Temporal slot suppliers can meet your needs.

### Implement Custom Slot Suppliers {#custom-slot-implementation}

Implement your own Slot Supplier to control how Workers are allocated Tasks and manage the processing of Workflows, Activities, and Nexus Operations.
Custom Slot Suppliers let you fine-tune task processing based on your application's needs.

Each SDK's reference documentation explains the specifics of the interface, but the core concepts are consistent across SDKs:

| Language                                               | Slot Supplier Reference                                                                                                  |
| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ |
|      | [`SlotSupplier`](https://pkg.go.dev/go.temporal.io/sdk/worker#SlotSupplier)                                              |
|        | [`SlotSupplier`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/worker/tuning/SlotSupplier.html) |
|      | [`CustomSlotSupplier`](https://python.temporal.io/temporalio.worker.CustomSlotSupplier.html)                             |
|  | [`CustomSlotSupplier`](https://typescript.temporal.io/api/interfaces/worker.CustomSlotSupplier)                          |
|      | [`CustomSlotSupplier`](https://dotnet.temporal.io/api/Temporalio.Worker.Tuning.CustomSlotSupplier.html)                  |

Slot Suppliers issue `SlotPermit`s.
These represent the right to use a slot of a specific type, namely Workflow, Activity, Local Activity, or Nexus.
You control whether a Worker can perform certain tasks by issuing or withholding permits.

Custom Slot Suppliers must implement these functions:

- `reserveSlot` - Called before polling for new tasks. Your implementation can block and must return a Slot Permit once it decides to accept new work.
- `tryReserveSlot` - Called for slot reservations in cases like eager activity processing. This must not block.
- `markSlotUsed` - Called when a slot is about to be used for a task (not while it’s held during polling). It provides information about the task.
- `releaseSlot` - Called when a slot is no longer needed, whether or not it was used.

Custom policies require more effort, but provide finer control over Task processing.
By implementing your own Slot Supplier, you can tailor how Workflows, Activities, and Nexus Operations are handled, optimizing performance for your specific needs.

### Slot supplier throttles

Auto-tuned suppliers may diverge from requested thresholds.
The resources a given Task will use can't be known ahead of time.
There is a fundamental tradeoff between how quickly a slot supplier is willing to accept Tasks and how well it can respect the defined thresholds.

Slot throttling is a mechanism to control the rate at which new slots for concurrent tasks are made available for processing.
This concept is part of the resource-based auto-tuning feature for Workers.
By waiting a brief period between making slots available, the Worker can assess how resource usage has changed since the last task began processing

This throttle is called `rampThrottle` in the SDK options for resource-based slot suppliers.
It defines the minimum time the Worker will wait between handing out new slots after passing the minimum slots number.

If a just-started worker were to have no throttle, and there was a backlog of Tasks, it might immediately accept 100 Tasks at once.
If each Task allocated 1GB of RAM, the Worker would likely run out of memory and crash.
The throttle enforces a wait before handing out new slots (after a minimum number of slots have been occupied) so you can measure newly consumed resources.

## Performance tuning examples {#examples}

The following examples show how to create and provision composite Worker tuners and set other
performance related options.
Each tuner provides slot suppliers for various Task types.
These examples focus on Activities and Local Activities, since Workflow Tasks normally do not need resource-based tuning.

### Go SDK

```go
// Using the ResourceBasedTuner in worker options
tuner, err := resourcetuner.NewResourceBasedTuner(resourcetuner.ResourceBasedTunerOptions{
    TargetMem: 0.8,
    TargetCpu: 0.9,
})
if err != nil {
  return err
}
workerOptions := worker.Options{
    Tuner: tuner
}
// Combining different types
options := DefaultResourceControllerOptions()
options.MemTargetPercent = 0.8
options.CpuTargetPercent = 0.9
controller := NewResourceController(options)
wfSS, err := worker.NewFixedSizeSlotSupplier(10)
if err != nil {
  return err
}
actSS := &ResourceBasedSlotSupplier{controller: controller,
    options: defaultActivityResourceBasedSlotSupplierOptions()}
laSS := &ResourceBasedSlotSupplier{controller: controller,
    options: defaultActivityResourceBasedSlotSupplierOptions()}
nexusSS, err := worker.NewFixedSizeSlotSupplier(10)
if err != nil {
  return err
}
compositeTuner, err := worker.NewCompositeTuner(worker.CompositeTunerOptions{
    WorkflowSlotSupplier:      wfSS,
    ActivitySlotSupplier:      actSS,
    LocalActivitySlotSupplier: laSS,
    NexusSlotSupplier:         nexusSS,
})
if err != nil {
  return err
}
workerOptions := worker.Options{
    Tuner: compositeTuner
}
```

### Java SDK

```java
// Just resource based
WorkerOptions.newBuilder()
    .setWorkerTuner(
        ResourceBasedTuner.newBuilder()
            .setControllerOptions(
                ResourceBasedControllerOptions.newBuilder(0.8, 0.9).build())
            .build())
    .build())
// Combining different types
SlotSupplier<WorkflowSlotInfo> workflowTaskSlotSupplier = new FixedSizeSlotSupplier<>(10);
SlotSupplier<ActivitySlotInfo> activityTaskSlotSupplier =
    ResourceBasedSlotSupplier.createForActivity(
        resourceController, ResourceBasedTuner.DEFAULT_ACTIVITY_SLOT_OPTIONS);
SlotSupplier<LocalActivitySlotInfo> localActivitySlotSupplier =
    ResourceBasedSlotSupplier.createForLocalActivity(
        resourceController, ResourceBasedTuner.DEFAULT_ACTIVITY_SLOT_OPTIONS);
SlotSupplier<NexusSlotInfo> nexusSlotSupplier = new FixedSizeSlotSupplier<>(10);

WorkerOptions.newBuilder()
    .setWorkerTuner(
        new CompositeTuner(
            workflowTaskSlotSupplier,
            activityTaskSlotSupplier,
            localActivitySlotSupplier,
            nexusSlotSupplier))
    .build();
```

### TypeScript SDK

```tsx
// Just resource based
const resourceBasedTunerOptions: ResourceBasedTunerOptions = {
  targetMemoryUsage: 0.8,
  targetCpuUsage: 0.9,
};
const workerOptions = {
  tuner: {
    tunerOptions: resourceBasedTunerOptions,
  },
};
// Combining different types
const resourceBasedTunerOptions: ResourceBasedTunerOptions = {
  targetMemoryUsage: 0.8,
  targetCpuUsage: 0.9,
};
const workerOptions = {
  tuner: {
    activityTaskSlotSupplier: {
      type: 'resource-based',
      tunerOptions: resourceBasedTunerOptions,
    },
    workflowTaskSlotSupplier: {
      type: 'fixed-size',
      numSlots: 10,
    },
    localActivityTaskSlotSupplier: {
      type: 'resource-based',
      tunerOptions: resourceBasedTunerOptions,
    },
  },
};
```

### Python SDK

```python