Environment Configuration
Temporal CLI and SDKs support configuring a Temporal Client using environment variables and TOML configuration files, rather than setting connection options programmatically in your code. This decouples connection settings from application logic, making it easier to manage different environments such as development, staging, and production without code changes.
This feature is currently in Pre-release in the Go and Python Temporal SDKs, as well as the Temporal CLI.
Configuration methods
You can configure your client using a TOML file, environment variables, or a combination of both. The configuration is loaded with a specific order of precedence:
- Environment variables: These have the highest precedence. If an environment variable defines a setting, it will always override any value set in a configuration file. This makes it easy to provide secrets in dynamic environments.
- TOML configuration file: A TOML file can be used to define one or more configuration profiles. This file is located
by checking the following sources in order:
- The path specified by the
TEMPORAL_CONFIG_FILEenvironment variable. - The default configuration path for your operating system:
- Linux:
~/.config/temporalio/temporal.toml - macOS:
$HOME/Library/Application Support/temporal/temporal.toml - Windows:
%AppData%\temporal\temporal.toml
- Linux:
- The path specified by the
Configuration profiles
You can use configuration profiles to maintain separate configurations within a single file for different environments.
The Temporal client uses the default profile unless you specify another via the TEMPORAL_PROFILE environment
variable or in the SDK's load options. If a requested profile doesn't exist, the application will return an error.
Configuration settings
The following table details all available settings, their corresponding environment variables, and their TOML file paths.
| Setting | Environment Variable | TOML Path | Description |
|---|---|---|---|
| Configuration File Path | TEMPORAL_CONFIG_FILE | NA | Path to the TOML configuration file |
| Server Address | TEMPORAL_ADDRESS | profile.<name>.address | The host and port of the Temporal Frontend service (e.g., "localhost:7233"). |
| Namespace | TEMPORAL_NAMESPACE | profile.<name>.namespace | The Temporal Namespace to connect to. |
| API Key | TEMPORAL_API_KEY | profile.<name>.api_key | An API key for authentication. If present, TLS is enabled by default. |
| Enable/Disable TLS | TEMPORAL_TLS | profile.<name>.tls.disabled | Set to "true" to enable TLS, "false" to disable. In TOML, disabled = true turns TLS off. |
| Client Certificate | TEMPORAL_TLS_CLIENT_CERT_DATA | profile.<name>.tls.client_cert_data | The raw PEM data containing the client's public TLS certificate. Alternatively, you can use TEMPORAL_TLS_CLIENT_CERT_PATH to provide a path to the certificate or the TOML profile.<name>.tls.client_cert_path. |
| Client Certificate Path | TEMPORAL_TLS_CLIENT_CERT_PATH | profile.<name>.tls.client_cert_path | A filesystem path to the client's public TLS certificate. Alternatively, you can provide the raw PEM data using TEMPORAL_TLS_CLIENT_CERT_DATA or the TOML profile.<name>.tls.client_cert_data. |
| Client Key | TEMPORAL_TLS_CLIENT_KEY_DATA | profile.<name>.tls.client_key_data | The raw PEM data containing the client's private TLS key. Alternatively, you can use TEMPORAL_TLS_CLIENT_KEY_PATH to provide a path to the key or the TOML profile.<name>.tls.client_key_path. |
| Client Key Path | TEMPORAL_TLS_CLIENT_KEY_PATH | profile.<name>.tls.client_key_path | A filesystem path to the client's private TLS key. Alternatively, you can provide the raw PEM data using TEMPORAL_TLS_CLIENT_KEY_DATA or the TOML profile.<name>.tls.client_key_data. |
| Server CA Cert | TEMPORAL_TLS_SERVER_CA_CERT_DATA | profile.<name>.tls.server_ca_cert_data | The raw PEM data for the Certificate Authority certificate used to verify the server. Alternatively, you can use TEMPORAL_TLS_SERVER_CA_CERT_PATH to provide a path or the TOML profile.<name>.tls.server_ca_cert_path. |
| Server CA Cert Path | TEMPORAL_TLS_SERVER_CA_CERT_PATH | profile.<name>.tls.server_ca_cert_path | A filesystem path to the Certificate Authority certificate. Alternatively, you can provide the raw PEM data using TEMPORAL_TLS_SERVER_CA_CERT_DATA or the TOML profile.<name>.tls.server_ca_cert_data. |
| TLS Server Name | TEMPORAL_TLS_SERVER_NAME | profile.<name>.tls.server_name | Overrides the server name used for Server Name Indication (SNI) in the TLS handshake. |
| Disable Host Verification | TEMPORAL_TLS_DISABLE_HOST_VERIFICATION | profile.<name>.tls.disable_host_verification | A boolean to disable server hostname verification. Use with caution. Not supported by all SDKs. |
| Codec Endpoint | TEMPORAL_CODEC_ENDPOINT | profile.<name>.codec.endpoint | The endpoint for a remote Data Converter. This is not supported by all SDKs. SDKs that support this configuration don't apply it by default. Intended mostly for CLI use. |
| Codec Auth | TEMPORAL_CODEC_AUTH | profile.<name>.codec.auth | The authorization header value for the remote data converter. |
| gRPC Metadata | TEMPORAL_GRPC_META_* | profile.<name>.grpc_meta | Sets gRPC headers. The part after _META_ becomes the header key (e.g., _SOME_KEY -> some-key). |
TOML Configuration Example
Here is an example temporal.toml file that defines two profiles: default for local development and prod for production.
# 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]
# TLS is auto-enabled when this TLS config or API key is present, but you can configure it explicitly
# disabled = false
# Use certificate files for mTLS
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"
# Staging profile with inline certificate data
[profile.staging]
address = "staging.temporal.example.com:7233"
namespace = "staging"
[profile.staging.tls]
# Example of providing certificate data directly (base64 or PEM format)
client_cert_data = """-----BEGIN CERTIFICATE-----
MIICertificateDataHere...
-----END CERTIFICATE-----"""
client_key_data = """-----BEGIN PRIVATE KEY-----
MIIPrivateKeyDataHere...
-----END PRIVATE KEY-----"""
CLI Integration
The Temporal CLI tool includes temporal config commands that allow you to read and write to the TOML configuration
file. This provides a convenient way to manage your connection profiles without manually editing the file.
temporal config get <property>: Reads a specific value from the current profile.temporal config set <property> <value>: Sets a property in the current profile.temporal config delete <property>: Deletes a property from the current profile.temporal config list: Lists all available profiles in the config file.
These CLI commands directly manipulate the temporal.toml file. This differs from the SDKs, which only read from the
file and environment at runtime to establish a client connection. The CLI is a tool for managing the configuration
source, while the SDKs are consumers of that configuration. You can select a profile for the CLI to use with the
--profile flag. For example, temporal --profile prod ....
The following code blocks provide copy-paste-friendly examples for setting up CLI profiles for both local development and Temporal Cloud.
- Local + Prod with Cloud API key
- API key + advanced options
This example shows how to set up a default profile for local development and a prod profile for Temporal Cloud using
an API key.
# (Optional) initialize the default profile for local development
temporal config set --prop address --value "localhost:7233"
temporal config set --prop namespace --value "default"
# Configure a Temporal Cloud profile that authenticates with an API key
temporal --profile prod config set --prop address --value "<region>.<cloud_provider>.api.temporal.io:7233"
temporal --profile prod config set --prop namespace --value "<namespace_id>.<account_id>"
temporal --profile prod config set --prop api_key --value "<your-api-key>"
This example shows how to set up a more advanced Temporal Cloud profile with TLS overrides and custom gRPC metadata.
# Base API key properties (replace the placeholders)
temporal --profile prod config set --prop address --value "<region>.<cloud_provider>.api.temporal.io:7233"
temporal --profile prod config set --prop namespace --value "<namespace_id>.<account_id>"
temporal --profile prod config set --prop api_key --value "<your-api-key>"
# Optional TLS overrides (only needed when you must pin certs or tweak SNI)
temporal --profile prod config set --prop tls.server_name --value "<namespace_id>.<account_id>"
temporal --profile prod config set --prop tls.ca_cert_path --value "/path/to/ca.pem"
# Optional gRPC metadata for observability or routing
temporal --profile prod config set --prop grpc_meta.environment --value "production"
temporal --profile prod config set --prop grpc_meta.service-version --value "v1.2.3"
Load configuration profile and environment variables
If you don't specify a profile, the SDKs load the default profile and the environment variables. If you haven't set
TEMPORAL_CONFIG_FILE, the SDKs will look for the configuration file in the default location. Refer to
Configuration methods for the default locations for your operating system.
No matter what profile you choose to load, environment variables are always loaded when you use the APIs in the environmental configuration package to load Temporal Client connection options. They always take precedence over TOML file settings in the profiles.
To load the default profile along with any environment variables in Go, use the
envconfig.MustLoadDefaultClientOptions() function from the temporalio.envconfig package.
package main
import (
"fmt"
"log"
"go.temporal.io/sdk/client"
"go.temporal.io/sdk/contrib/envconfig"
)
func main() {
// Loads the "default" profile from the standard location and environment variables.
c, err := client.Dial(envconfig.MustLoadDefaultClientOptions())
if err != nil {
log.Fatalf("Failed to create client: %v", err)
}
defer c.Close()
fmt.Printf("✅ Connected to Temporal namespace %q on %s\n", c.Options().Namespace, c.Options().HostPort)
}
To load the default profile along with any environment variables in Python, use the ClientConfigProfile.load()
method from the temporalio.envconfig package.
import asyncio
from temporalio.client import Client
from temporalio.envconfig import ClientConfigProfile
async def main():
# Load the "default" profile from default locations and environment variables.
default_profile = ClientConfigProfile.load()
connect_config = default_profile.to_client_connect_config()
# Connect to the client using the loaded configuration.
client = await Client.connect(**connect_config)
print(f"✅ Client connected to {client.service_client.config.target_host} in namespace '{client.namespace}'")
if __name__ == "__main__":
asyncio.run(main())
To load the default profile along with any environment variables in .NET C#, use the
ClientEnvConfig.LoadClientConnectOptions() method from the Temporalio.Client.EnvConfig package.
using Temporalio.Client;
using Temporalio.Client.EnvConfig;
namespace TemporalioSamples.EnvConfig;
/// <summary>
/// Sample demonstrating loading the default environment configuration profile
/// from a TOML file.
/// </summary>
public static class LoadFromFile
{
public static async Task RunAsync()
{
Console.WriteLine("--- Loading default profile from config.toml ---");
try
{
// For this sample to be self-contained, we explicitly provide the path to
// the config.toml file included in this directory.
// By default though, the config.toml file will be loaded from
// ~/.config/temporalio/temporal.toml (or the equivalent standard config directory on your OS).
var configFile = Path.Combine(Directory.GetCurrentDirectory(), "config.toml");
// LoadClientConnectOptions is a helper that loads a profile and prepares
// the config for TemporalClient.ConnectAsync. By default, it loads the
// "default" profile.
var connectOptions = ClientEnvConfig.LoadClientConnectOptions(new ClientEnvConfig.ProfileLoadOptions
{
ConfigSource = DataSource.FromPath(configFile),
});
Console.WriteLine($"Loaded 'default' profile from {configFile}.");
Console.WriteLine($" Address: {connectOptions.TargetHost}");
Console.WriteLine($" Namespace: {connectOptions.Namespace}");
if (connectOptions.RpcMetadata?.Count > 0)
{
Console.WriteLine($" gRPC Metadata: {string.Join(", ", connectOptions.RpcMetadata.Select(kv => $"{kv.Key}={kv.Value}"))}");
}
Console.WriteLine("\nAttempting to connect to client...");
var client = await TemporalClient.ConnectAsync(connectOptions);
Console.WriteLine("✅ Client connected successfully!");
// Test the connection by checking the service
var sysInfo = await client.Connection.WorkflowService.GetSystemInfoAsync(new());
Console.WriteLine("✅ Successfully verified connection to Temporal server!\n{0}", sysInfo);
}
catch (Exception ex) when (ex is not OperationCanceledException)
{
Console.WriteLine($"❌ Failed to connect: {ex.Message}");
}
}
}
To load the default profile along with any environment variables in Ruby, use the
EnvConfig::ClientConfig.load_client_connect_options() method from the temporalio.env_config package.
require 'temporalio/client'
require 'temporalio/env_config'
def main
puts '--- Loading default profile from config.toml ---'
# For this sample to be self-contained, we explicitly provide the path to
# the config.toml file included in this directory.
# By default though, the config.toml file will be loaded from
# ~/.config/temporalio/temporal.toml (or the equivalent standard config directory on your OS).
config_file = File.join(__dir__, 'config.toml')
# load_client_connect_options is a helper that loads a profile and prepares
# the configuration for Client.connect. By default, it loads the
# "default" profile.
args, kwargs = Temporalio::EnvConfig::ClientConfig.load_client_connect_options(
config_source: Pathname.new(config_file)
)
puts "Loaded 'default' profile from #{config_file}."
puts " Address: #{args[0]}"
puts " Namespace: #{args[1]}"
puts " gRPC Metadata: #{kwargs[:rpc_metadata]}"
puts "\nAttempting to connect to client..."
begin
client = Temporalio::Client.connect(*args, **kwargs)
puts '✅ Client connected successfully!'
sys_info = client.workflow_service.get_system_info(Temporalio::Api::WorkflowService::V1::GetSystemInfoRequest.new)
puts "✅ Successfully verified connection to Temporal server!\n#{sys_info}"
rescue StandardError => e
puts "❌ Failed to connect: #{e}"
end
end
Load configuration from a custom path
To load configuration from a non-standard file location without relying on the TEMPORAL_CONFIG_FILE environment
variable, you can use a function from the temporalio.envconfig package. The specific method you need to call depends
on the SDK you are using.
This is useful if you store application-specific configurations separately. Loading connection options using this method will still respect environment variables, which take precedence over the file settings.
To load a specific profile from a custom filepath in Go, use the envconfig.LoadClientOptions() function with the
ConfigFilePath field set in the LoadClientOptionsRequest struct. Use the ConfigFileProfile field to specify the
profile name.
After loading the connection options, you can override specific settings programmatically before passing them to
client.Dial(). Refer to the GO SDK API documentation for
all available options.
package main
import (
"fmt"
"log"
"go.temporal.io/sdk/client"
"go.temporal.io/sdk/contrib/envconfig"
)
func main() {
// Load a specific profile from the TOML config file.
// This requires a [profile.prod] section in your config.
opts, err := envconfig.LoadClientOptions(envconfig.LoadClientOptionsRequest{
ConfigFileProfile: "prod",
})
if err != nil {
log.Fatalf("Failed to load 'prod' profile: %v", err)
}
// Programmatically override the Namespace value.
opts.Namespace = "new-namespace"
c, err := client.Dial(opts)
if err != nil {
log.Fatalf("Failed to connect using 'prod' profile: %v", err)
}
defer c.Close()
fmt.Printf("✅ Connected to Temporal namespace %q on %s using 'prod' profile\n", c.Options().Namespace, c.Options().HostPort)
}
To load a specific profile from a custom path in Python, use the ClientConfig.load_client_connect_config() method with
the config_file parameter. In this example, we construct the path to a config.toml file located in the same
directory as the script.
After loading the connection options, you can override specific settings programmatically before passing them to
Client.connect().
import asyncio
from pathlib import Path
from temporalio.client import Client
from temporalio.envconfig import ClientConfig
async def main():
"""
Demonstrates loading a named profile and overriding values programmatically.
"""
print("--- Loading 'staging' profile with programmatic overrides ---")
config_file = Path(__file__).parent / "config.toml"
profile_name = "staging"
print(
"The 'staging' profile in config.toml has an incorrect address (localhost:9999)."
)
print("We'll programmatically override it to the correct address.")
# Load the 'staging' profile.
connect_config = ClientConfig.load_client_connect_config(
profile=profile_name,
config_file=str(config_file),
)
# Override the target host to the correct address.
# This is the recommended way to override configuration values.
connect_config["target_host"] = "localhost:7233"
print(f"\nLoaded '{profile_name}' profile from {config_file} with overrides.")
print(
f" Address: {connect_config.get('target_host')} (overridden from localhost:9999)"
)
print(f" Namespace: {connect_config.get('namespace')}")
print("\nAttempting to connect to client...")
try:
await Client.connect(**connect_config) # type: ignore
print("✅ Client connected successfully!")
except Exception as e:
print(f"❌ Failed to connect: {e}")
if __name__ == "__main__":
asyncio.run(main())
To load a specific profile from a custom path in .NET C#, use the ClientEnvConfig.LoadClientConnectOptions() method
with the ProfileLoadOptions parameter. Use the Profile property to specify the profile name and the ConfigSource
property to specify the file path.
After loading the connection options, you can override specific settings programmatically before passing them to
TemporalClient.ConnectAsync(). Refer to the
C# SDK API documentation for all available options.
using Temporalio.Client;
using Temporalio.Client.EnvConfig;
namespace TemporalioSamples.EnvConfig;
/// <summary>
/// Sample demonstrating loading a named environment configuration profile and
/// programmatically overriding its values.
/// </summary>
public static class LoadProfile
{
public static async Task RunAsync()
{
Console.WriteLine("--- Loading 'staging' profile with programmatic overrides ---");
try
{
var configFile = Path.Combine(Directory.GetCurrentDirectory(), "config.toml");
var profileName = "staging";
Console.WriteLine("The 'staging' profile in config.toml has an incorrect address (localhost:9999).");
Console.WriteLine("We'll programmatically override it to the correct address.");
// Load the 'staging' profile
var connectOptions = ClientEnvConfig.LoadClientConnectOptions(new ClientEnvConfig.ProfileLoadOptions
{
Profile = profileName,
ConfigSource = DataSource.FromPath(configFile),
});
// Override the target host to the correct address.
// This is the recommended way to override configuration values.
connectOptions.TargetHost = "localhost:7233";
Console.WriteLine($"\nLoaded '{profileName}' profile from {configFile} with overrides.");
Console.WriteLine($" Address: {connectOptions.TargetHost} (overridden from localhost:9999)");
Console.WriteLine($" Namespace: {connectOptions.Namespace}");
Console.WriteLine("\nAttempting to connect to client...");
var client = await TemporalClient.ConnectAsync(connectOptions);
Console.WriteLine("✅ Client connected successfully!");
// Test the connection by checking the service
var sysInfo = await client.Connection.WorkflowService.GetSystemInfoAsync(new());
Console.WriteLine("✅ Successfully verified connection to Temporal server!\n{0}", sysInfo);
}
catch (Exception ex) when (ex is not OperationCanceledException)
{
Console.WriteLine($"❌ Failed to connect: {ex.Message}");
}
}
}
To load a specific profile from a custom path in Ruby, use the EnvConfig::ClientConfig.load_client_connect_options()
method with the config_source parameter. In this example, we construct the path to a config.toml file located in the
same directory as the script. Use the profile parameter to specify the profile name.
After loading the connection options, you can override specific settings programmatically before passing them to
Client.connect(). Refer to the Ruby SDK API documentation for
all available options.
require 'temporalio/client'
require 'temporalio/env_config'
def main
puts "--- Loading 'staging' profile with programmatic overrides ---"
config_file = File.join(__dir__, 'config.toml')
profile_name = 'staging'
puts "The 'staging' profile in config.toml has an incorrect address (localhost:9999)."
puts "We'll programmatically override it to the correct address."
# Load the 'staging' profile.
args, kwargs = Temporalio::EnvConfig::ClientConfig.load_client_connect_options(
profile: profile_name,
config_source: Pathname.new(config_file)
)
# Override the target host to the correct address.
# This is the recommended way to override configuration values.
args[0] = 'localhost:7233'
puts "\nLoaded '#{profile_name}' profile from #{config_file} with overrides."
puts " Address: #{args[0]} (overridden from localhost:9999)"
puts " Namespace: #{args[1]}"
puts "\nAttempting to connect to client..."
begin
client = Temporalio::Client.connect(*args, **kwargs)
puts '✅ Client connected successfully!'
sys_info = client.workflow_service.get_system_info(Temporalio::Api::WorkflowService::V1::GetSystemInfoRequest.new)
puts "✅ Successfully verified connection to Temporal server!\n#{sys_info}"
rescue StandardError => e
puts "❌ Failed to connect: #{e}"
end
end
main if $PROGRAM_NAME == __FILE__