Skip to main content

Temporal Client - Rust SDK

A Temporal Client lets your application communicate with the Temporal Service. Use it to start Workflow Executions, send Signals, run Queries, fetch Workflow results, and more.

This page shows how to do the following using the Rust SDK and Temporal Client:

A Temporal Client can't be created and used inside Workflow code. However, using a Temporal Client inside an Activity is acceptable when you need to communicate with the Temporal Service.

Connect to development Temporal Service

In Rust, create a client by establishing a Connection and then constructing a Client. You can provide connection options directly in code or load them from environment variables.

When you are running Temporal locally, the minimal setup is typically a local server address and the default Namespace.

You can use a TOML configuration file to set connection options for the Temporal Client. The configuration file supports multiple profiles, each with its own connection options.

If you don't specify a configuration file path, the SDK looks in the default OS-specific location. Environment variables take precedence over values from the configuration file.

For example, the following TOML file defines two profiles:

temporal.toml
# Default profile for local development
[profile.default]
address = "localhost:7233"
namespace = "default"

# Optional: Add custom gRPC headers
[profile.default.grpc_meta]
my-custom-header = "development-value"
trace-id = "dev-trace-123"

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

# TLS configuration for production
[profile.prod.tls]
client_cert_path = "/etc/temporal/certs/client.pem"
client_key_path = "/etc/temporal/certs/client.key"

# Custom headers for production
[profile.prod.grpc_meta]
environment = "production"
service-version = "v1.2.3"

Load the configuration and connect with the prod profile as follows:

use temporalio_client::{
Client, ClientOptions, Connection
};
use temporalio_common::{envconfig::LoadClientConfigProfileOptions, telemetry::TelemetryOptions};
use temporalio_sdk::{Worker, WorkerOptions};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let runtime = CoreRuntime::new_assume_tokio(
RuntimeOptions::builder()
.telemetry_options(TelemetryOptions::builder().build())
.build()?,
)?;
let (conn_opts, client_opts) =
ClientOptions::load_from_config(LoadClientConfigProfileOptions {
config_file_profile: "prod".to_string().into(),
..Default::default()
})?;
let connection = Connection::connect(conn_opts).await?;
let client = Client::new(connection, client_opts)?;

...

Ok(())
}

Connect to Temporal Cloud

You can connect to Temporal Cloud using either an API key or mTLS. Connection to Temporal Cloud or any secured Temporal Service requires additional connection options compared to connecting to an unsecured local development instance:

  • Your authentication credentials:
    • For API key authentication, provide the API key.
    • If you are using mTLS, provide the mTLS CA certificate and mTLS private key.
  • Your Namespace and Account ID combination in the format <namespace_id>.<account_id>
  • The recommended gRPC endpoint for your Namespace, such as <namespace>.<account>.tmprl.cloud:7233

For more information about managing and generating client certificates for Temporal Cloud, see How to manage certificates in Temporal Cloud.

You can provide these connection options using environment variables, a configuration file, or directly in code.

You can define a Temporal Cloud profile in temporal.toml:

[profile.api]
address = "your-namespace.a1b2c.tmprl.cloud:7233"
namespace = "your-namespace"
api_key = "your-api-key-here"

If you want to use mTLS instead of an API key:

[profile.mtls]
address = "your-namespace.a1b2c.tmprl.cloud:7233"
namespace = "your-namespace"
tls_client_cert_data = "your-tls-client-cert-data"
tls_client_key_path = "your-tls-client-key-path"

Then load the profile and connect:

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

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let (conn_opts, client_opts) =
ClientOptions::load_from_config(LoadClientConfigProfileOptions {
config_file_profile: "api".to_string().into(),
..Default::default()
})?;

let runtime = CoreRuntime::new_assume_tokio(RuntimeOptions::builder().build()?)?;

// Client setup
let connection = Connection::connect(conn_opts).await?;
let client = Client::new(connection, client_opts)?;

println!("Connected to Temporal Cloud!");
Ok(())
}

Start a Workflow Execution

To start a Workflow Execution, supply:

Starting a Workflow Execution creates the first WorkflowExecutionStarted Event in the Event History, followed by the first WorkflowTaskScheduled Event.

In Rust, use start_workflow() to start a Workflow and return a handle.

let handle = client.start_workflow(
GreetingsWorkflow::run,
(),
WorkflowStartOptions::new(
"my-task-queue",
"greetings-workflow-10",
).build()
).await?;

Set a Workflow's Task Queue

In most cases, the Task Queue is a required Workflow option.

For a Workflow to make progress, at least one Worker must be polling the same Task Queue.

In Rust, set the Task Queue in WorkflowStartOptions:

let handle = client
.start_workflow(
GreetingsWorkflow::run,
(),
WorkflowStartOptions::new(
"your-task-queue",
"your-workflow-id"
).build(),
).await?;

Set a Workflow Id

You must set a Workflow Id.

A Workflow Id should usually map to a business process or business entity identifier, such as an order ID or customer ID.

In Rust, set the Workflow Id in WorkflowStartOptions:

let handle = client
.start_workflow(
GreetingsWorkflow::run,
(),
WorkflowStartOptions::new(
"your-task-queue",
"your-workflow-id"
).build(),
).await?;

Get the results of a Workflow Execution

If starting a Workflow succeeds, you get a Workflow handle. You can use that handle to wait for the result, describe the Workflow, or interact with it through Signals, Queries, and Updates.

To get the result of a newly started Workflow:

let handle = client
.start_workflow(
GreetingsWorkflow::run,
(),
WorkflowStartOptions::new(
"your-task-queue",
"your-workflow-id"
).build(),
).await?;

let result = handle.get_result(WorkflowGetResultOptions::default()).await;

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