Skip to main content

Temporal Client - Rust SDK

A Temporal Client enables you to communicate with the Temporal Service. Communication with a Temporal Service lets you perform actions such as starting Workflow Executions, sending Signals to Workflow Executions, sending Queries to Workflow Executions, getting the results of a Workflow Execution, and terminating Workflow Executions.

This page shows you how to do the following using the Rust SDK:

caution

A Temporal Client cannot be initialized and used inside a Workflow. However, it is acceptable and common to use a Temporal Client inside an Activity to communicate with a Temporal Service.

Connect to a development Temporal Service

To connect to a Temporal Service running locally on the default port (7233):

use temporalio_client::{Client, ClientOptions, Connection, envconfig::LoadClientConfigProfileOptions};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Load configuration from environment variables or config file
let (conn_options, client_options) = ClientOptions::load_from_config(
LoadClientConfigProfileOptions::default()
)?;

// Create connection
let connection = Connection::connect(conn_options).await?;

// Create client
let client = Client::new(connection, client_options);

Ok(())
}

The SDK automatically loads configuration from:

  1. Environment variables (highest priority)
  2. Configuration file at path specified by TEMPORAL_CONFIG_FILE
  3. Default configuration file at ~/.config/temporalio/temporal.toml

For a list of all available environment variables and their defaults, refer to Environment Configuration.

Configure Client with Code

If you prefer to configure the client directly in code:

use temporalio_client::{Client, ClientOptions, WorkflowServiceStubsOptions};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Configure connection options
let conn_options = WorkflowServiceStubsOptions::new()
.target_url("localhost:7233".parse()?)
.build();

// Configure client options
let client_options = ClientOptions::new()
.namespace("default");

// Create connection and client
let connection = Connection::connect(conn_options).await?;
let client = Client::new(connection, client_options);

Ok(())
}

Connect to Temporal Cloud

To connect to Temporal Cloud, you need:

  • Your Namespace and Account ID (in format namespace.account-id)
  • Either an API Key or mTLS certificates

Connect with API Key

use temporalio_client::{Client, ClientOptions, WorkflowServiceStubsOptions};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let namespace = "your-namespace.abc123"; // Your namespace.account-id
let api_key = "your-api-key"; // Your Temporal Cloud API key

let conn_options = WorkflowServiceStubsOptions::new()
.target_url("your-namespace.abc123.tmprl.cloud:7233".parse()?)
.api_key(api_key.into())
.build();

let client_options = ClientOptions::new()
.namespace(namespace);

let connection = Connection::connect(conn_options).await?;
let client = Client::new(connection, client_options);

Ok(())
}

Connect with mTLS Certificates

use temporalio_client::{Client, ClientOptions, WorkflowServiceStubsOptions};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let namespace = "your-namespace.abc123";

let conn_options = WorkflowServiceStubsOptions::new()
.target_url("your-namespace.abc123.tmprl.cloud:7233".parse()?)
.client_cert_path("/path/to/client.pem".into())
.client_key_path("/path/to/client.key".into())
.build();

let client_options = ClientOptions::new()
.namespace(namespace);

let connection = Connection::connect(conn_options).await?;
let client = Client::new(connection, client_options);

Ok(())
}

Start a Workflow Execution

Use client.start_workflow() to start a Workflow Execution:

use temporalio_client::{Client, WorkflowOptions};
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = /* ... setup ... */;

// Start a workflow
let handle = client.start_workflow(
GreetingWorkflow::run,
"World".to_string(),
WorkflowOptions::new("my-task-queue", "greeting-1")
.workflow_execution_timeout(Some(Duration::from_secs(3600)))
.build()
).await?;

println!("Started workflow: {}", handle.workflow_id());

Ok(())
}

Workflow Execution Options

Common Workflow Options:

use temporalio_client::WorkflowOptions;
use std::time::Duration;

let options = WorkflowOptions::new("my-task-queue", "workflow-id-123")
// Maximum time the Workflow can execute
.workflow_execution_timeout(Some(Duration::from_secs(3600)))
// Maximum time between Workflow Task starts
.workflow_run_timeout(Some(Duration::from_secs(1800)))
// Maximum time for a single Workflow Task
.workflow_task_timeout(Some(Duration::from_secs(10)))
// ID to retry with for idempotency
.workflow_id_reuse_policy(WorkflowIdReusePolicy::AllowDuplicate)
// Retry policy for Workflow retries
.retry_policy(Some(RetryPolicy { /* ... */ }))
// Memo data (not searchable)
.memo(/* ... */)
// Search attributes (searchable, queryable)
.search_attributes(/* ... */)
.build();

Get Workflow Results

Use the workflow handle to get results:

// Get handle from start_workflow or by workflow ID
let handle = client.get_workflow_handle::<GreetingWorkflow>("workflow-id");

// Wait for result (blocking until complete)
let result = handle.get_result::<String>(GetWorkflowResultOptions::default()).await?;
println!("Workflow result: {}", result);

// OR get result immediately if available
match handle.get_result::<String>(GetWorkflowResultOptions::default()).wait_timeout(Duration::from_secs(0)).await {
Ok(result) => println!("Result: {}", result),
Err(_) => println!("Workflow still running"),
}

Send Signals to Workflows

Send a Signal to a running Workflow:

use temporalio_client::SignalOptions;

let handle = client.get_workflow_handle::<MyWorkflow>("workflow-id");

// Send a signal
handle.signal(
MyWorkflow::my_signal,
"signal-value".to_string(),
SignalOptions::default(),
).await?;

Query Workflows

Query a running Workflow for its state:

use temporalio_client::QueryOptions;

let handle = client.get_workflow_handle::<MyWorkflow>("workflow-id");

// Execute a query
let status = handle.query(
MyWorkflow::get_status,
(),
QueryOptions::default(),
).await?;

println!("Workflow status: {}", status);

Execute Updates

Execute an Update on a running Workflow:

use temporalio_client::UpdateOptions;

let handle = client.get_workflow_handle::<MyWorkflow>("workflow-id");

// Execute an update synchronously
let result = handle.execute_update(
MyWorkflow::my_update,
42,
UpdateOptions::default(),
).await?;

println!("Update result: {:?}", result);

Asynchronous Updates

Start an update and get the result later:

use temporalio_client::{StartUpdateOptions, WorkflowUpdateWaitStage};

let handle = client.get_workflow_handle::<MyWorkflow>("workflow-id");

// Start update and wait only until accepted
let update_handle = handle.start_update(
MyWorkflow::my_update,
42,
StartUpdateOptions::builder()
.wait_for_stage(WorkflowUpdateWaitStage::Accepted)
.build()
).await?;

// Do other work...

// Get result when ready
let result = update_handle.get_result().await?;

Cancel Workflows

Request cancellation of a running Workflow:

use temporalio_client::CancelWorkflowOptions;

let handle = client.get_workflow_handle::<MyWorkflow>("workflow-id");

// Request cancellation (allows graceful shutdown)
handle.cancel(
CancelWorkflowOptions::builder()
.reason("User requested cancellation")
.build()
).await?;

The Workflow will receive the cancellation request via ctx.cancelled() and can clean up gracefully.

Terminate Workflows

Immediately terminate a Workflow (without allowing cleanup):

use temporalio_client::TerminateWorkflowOptions;

let handle = client.get_workflow_handle::<MyWorkflow>("workflow-id");

// Terminate immediately
handle.terminate(
TerminateWorkflowOptions::builder()
.reason("Emergency: forcing shutdown")
.build()
).await?;

Unlike cancellation, termination is immediate and the Workflow cannot handle it.

List Workflows

Query and list running Workflows:

use temporalio_client::ListWorkflowsOptions;
use futures_util::StreamExt;

let mut stream = client.list_workflows(
"WorkflowType = 'MyWorkflow'",
ListWorkflowsOptions::builder()
.limit(10)
.build()
);

while let Some(result) = stream.next().await {
let execution = result?;
println!("Workflow: {} ({})", execution.id(), execution.workflow_type());
}

Best Practices

  1. Reuse Client instances: Create one Client and share it across your application
  2. Load configuration from environment: Use environment variables or config files for deployment flexibility
  3. Handle errors gracefully: Always check for connection errors and handle them appropriately
  4. Use meaningful Workflow IDs: Make it easy to track and query Workflows
  5. Set appropriate timeouts: Prevent Workflows from running indefinitely
  6. Use Search Attributes: Make your Workflows discoverable with searchable metadata

For more information, see Environment Configuration and Visibility.