Temporal Server uses YAML configuration files to define persistence, networking, security, and operational settings. This guide covers all configuration options with real examples.
Configuration File Structure
A complete configuration file has these top-level sections:
log : # Logging configuration
persistence : # Database and storage settings
global : # Global settings (TLS, metrics, membership)
services : # Individual service configuration
clusterMetadata : # Cluster identity and failover settings
dcRedirectionPolicy : # Cross-datacenter request routing
archival : # Workflow history archival
namespaceDefaults : # Default namespace settings
publicClient : # Client configuration for workers
dynamicConfigClient : # Dynamic configuration settings
Logging Configuration
Configure log output format and level:
log :
stdout : true
level : info # debug, info, warn, error
Output logs to stdout instead of files
Minimum log level: debug, info, warn, error
Persistence Configuration
Basic Setup
persistence :
numHistoryShards : 4
defaultStore : default
visibilityStore : visibility
datastores :
default :
# Database configuration
visibility :
# Visibility database configuration
Number of history shards. Higher values improve scalability. Recommendations :
Development: 4
Small production: 128-512
Large production: 1024-4096
Cannot be changed after initial deployment
MySQL Configuration
persistence :
numHistoryShards : 4
defaultStore : mysql-default
visibilityStore : mysql-visibility
datastores :
mysql-default :
sql :
pluginName : "mysql8"
databaseName : "temporal"
connectAddr : "127.0.0.1:3306"
connectProtocol : "tcp"
user : "temporal"
password : "temporal"
maxConns : 20
maxIdleConns : 20
maxConnLifetime : "1h"
tls :
enabled : false
caFile : ""
certFile : ""
keyFile : ""
enableHostVerification : false
serverName : ""
mysql-visibility :
sql :
pluginName : "mysql8"
databaseName : "temporal_visibility"
connectAddr : "127.0.0.1:3306"
connectProtocol : "tcp"
user : "temporal"
password : "temporal"
maxConns : 2
maxIdleConns : 2
maxConnLifetime : "1h"
PostgreSQL Configuration
persistence :
numHistoryShards : 4
defaultStore : postgres-default
visibilityStore : postgres-visibility
datastores :
postgres-default :
sql :
pluginName : "postgres12" # or "postgres12_pgx"
databaseName : "temporal"
connectAddr : "127.0.0.1:5432"
connectProtocol : "tcp"
user : "temporal"
password : "temporal"
maxConns : 20
maxIdleConns : 20
maxConnLifetime : "1h"
tls :
enabled : false
postgres-visibility :
sql :
pluginName : "postgres12"
databaseName : "temporal_visibility"
connectAddr : "127.0.0.1:5432"
connectProtocol : "tcp"
user : "temporal"
password : "temporal"
maxConns : 2
maxIdleConns : 2
maxConnLifetime : "1h"
Use postgres12_pgx for better performance with the pgx driver.
Cassandra Configuration
persistence :
numHistoryShards : 4
defaultStore : cass-default
visibilityStore : es-visibility # Cassandra not supported for visibility
datastores :
cass-default :
cassandra :
hosts : "127.0.0.1"
keyspace : "temporal"
port : 9042
user : ""
password : ""
maxConns : 20
tls :
enabled : false
caFile : ""
certFile : ""
keyFile : ""
enableHostVerification : false
serverName : ""
Cassandra is no longer supported for visibility stores. Use MySQL, PostgreSQL, or Elasticsearch.
Elasticsearch Configuration
For advanced visibility features:
persistence :
visibilityStore : es-visibility
datastores :
es-visibility :
elasticsearch :
version : "v7" # v7 or v8
logLevel : "error"
url :
scheme : "http" # or "https"
host : "127.0.0.1:9200"
username : ""
password : ""
indices :
visibility : "temporal_visibility_v1_dev"
# Optional secondary index for dual visibility
secondary_visibility : "temporal_visibility_v2_dev"
closeIdleConnectionsInterval : "15s"
Connection Pool Settings
Maximum number of connections to the database
Maximum number of idle connections to maintain
Maximum lifetime of a connection before it is closed
Tuning Guidelines :
# High throughput workloads
maxConns : 50
maxIdleConns : 25
maxConnLifetime : "30m"
# Resource-constrained environments
maxConns : 10
maxIdleConns : 5
maxConnLifetime : "2h"
Global Configuration
Membership Settings
global :
membership :
maxJoinDuration : 30s
broadcastAddress : "127.0.0.1"
Maximum time for a service to join the cluster ring
Address advertised to other cluster members. Leave empty for auto-detection.
Metrics Configuration
global :
metrics :
prometheus :
framework : "opentelemetry" # or "tally"
timerType : "histogram" # or "summary"
listenAddress : "127.0.0.1:8000"
Access metrics at http://localhost:8000/metrics global :
metrics :
statsd :
hostPort : "127.0.0.1:8125"
prefix : "temporal"
Metrics are pushed to StatsD daemon
Profiling Configuration
global :
pprof :
port : 7936 # Set to 0 to disable
Access profiling data:
http://localhost:7936/debug/pprof/heap
http://localhost:7936/debug/pprof/profile
http://localhost:7936/debug/pprof/goroutine
TLS Configuration
Internode TLS
Frontend TLS
Certificate Rotation
global :
tls :
refreshInterval : "0s" # Auto-refresh certificates
internode :
server :
requireClientAuth : true
certFile : "/certs/server-cert.pem"
keyFile : "/certs/server-key.pem"
clientCaFiles :
- "/certs/ca-cert.pem"
client :
serverName : "temporal-cluster"
disableHostVerification : false
rootCaFiles :
- "/certs/ca-cert.pem"
Secures communication between Temporal services (Frontend, History, Matching, Worker) global :
tls :
frontend :
server :
requireClientAuth : true
certFile : "/certs/frontend-cert.pem"
keyFile : "/certs/frontend-key.pem"
clientCaFiles :
- "/certs/client-ca-cert.pem"
client :
serverName : "temporal.example.com"
disableHostVerification : false
rootCaFiles :
- "/certs/ca-cert.pem"
Secures communication between clients and Frontend service global :
tls :
refreshInterval : "1h" # Check for cert changes hourly
expirationChecks :
warningWindow : "720h" # 30 days
errorWindow : "168h" # 7 days
checkInterval : "24h" # Check daily
Automatically reload certificates and warn before expiration
Authorization Configuration
global :
authorization :
jwtKeyProvider :
keySourceURIs :
- "https://auth.example.com/.well-known/jwks.json"
- "file:///etc/temporal/certs/public-key.pem"
refreshInterval : "1m"
permissionsClaimName : "permissions"
permissionsRegex : ""
authorizer : "" # Custom authorizer plugin
claimMapper : "" # Custom claim mapper plugin
Service Configuration
Frontend Service
services :
frontend :
rpc :
grpcPort : 7233
membershipPort : 6933
bindOnIP : "0.0.0.0"
httpPort : 7243
History Service
services :
history :
rpc :
grpcPort : 7234
membershipPort : 6934
bindOnIP : "0.0.0.0"
Matching Service
services :
matching :
rpc :
grpcPort : 7235
membershipPort : 6935
bindOnIP : "0.0.0.0"
Worker Service
services :
worker :
rpc :
grpcPort : 7239
membershipPort : 6939
bindOnIP : "0.0.0.0"
Internal Frontend Service
services :
internal-frontend :
rpc :
grpcPort : 7236
membershipPort : 6936
bindOnIP : "0.0.0.0"
httpPort : 7246
The internal-frontend service is optional and used for internal cross-cluster communication.
Single Cluster
clusterMetadata :
enableGlobalNamespace : false
failoverVersionIncrement : 10
masterClusterName : "active"
currentClusterName : "active"
clusterInformation :
active :
enabled : true
initialFailoverVersion : 1
rpcName : "frontend"
rpcAddress : "localhost:7233"
httpAddress : "localhost:7243"
dcRedirectionPolicy :
policy : "noop"
Multi-Cluster Setup
clusterMetadata :
enableGlobalNamespace : true
failoverVersionIncrement : 100
masterClusterName : "cluster-a"
currentClusterName : "cluster-a"
clusterInformation :
cluster-a :
enabled : true
initialFailoverVersion : 1
rpcName : "frontend"
rpcAddress : "cluster-a.example.com:7233"
httpAddress : "cluster-a.example.com:7243"
cluster-b :
enabled : true
initialFailoverVersion : 2
rpcName : "frontend"
rpcAddress : "cluster-b.example.com:7233"
httpAddress : "cluster-b.example.com:7243"
dcRedirectionPolicy :
policy : "all-apis-forwarding"
Enable global namespaces for multi-cluster replication
Version increment between clusters. Use larger values (100+) for multi-cluster.
Archival Configuration
Archive completed workflow histories for long-term storage:
File Store
S3
Google Cloud Storage
archival :
history :
state : "enabled" # enabled or disabled
enableRead : true
provider :
filestore :
fileMode : "0666"
dirMode : "0766"
visibility :
state : "enabled"
enableRead : true
provider :
filestore :
fileMode : "0666"
dirMode : "0766"
namespaceDefaults :
archival :
history :
state : "disabled" # Disabled by default
URI : "file:///mnt/temporal/archival"
visibility :
state : "disabled"
URI : "file:///mnt/temporal/vis-archival"
archival :
history :
state : "enabled"
enableRead : true
provider :
s3store :
region : "us-east-1"
endpoint : ""
s3ForcePathStyle : false
visibility :
state : "enabled"
enableRead : true
provider :
s3store :
region : "us-east-1"
namespaceDefaults :
archival :
history :
state : "disabled"
URI : "s3://my-bucket/temporal/archival"
visibility :
state : "disabled"
URI : "s3://my-bucket/temporal/vis-archival"
archival :
history :
state : "enabled"
enableRead : true
provider :
gstorage :
credentialsPath : "/etc/temporal/gcp-credentials.json"
visibility :
state : "enabled"
enableRead : true
provider :
gstorage :
credentialsPath : "/etc/temporal/gcp-credentials.json"
namespaceDefaults :
archival :
history :
state : "disabled"
URI : "gs://my-bucket/temporal/archival"
visibility :
state : "disabled"
URI : "gs://my-bucket/temporal/vis-archival"
Dynamic Configuration
dynamicConfigClient :
filepath : "/etc/temporal/config/dynamicconfig/docker.yaml"
pollInterval : "60s"
Dynamic configuration allows runtime changes without server restart. Example dynamic config file:
dynamicconfig/production.yaml
# Limit workflow execution history size
history.maxAutoResetPoints :
- value : 20
constraints :
namespace : "my-namespace"
# Configure retention period
system.defaultWorkflowExecutionRetentionPeriod :
- value : "30d"
# Set task queue limits
matching.numTaskqueueWritePartitions :
- value : 4
constraints :
namespace : "high-throughput-namespace"
Environment Variable Templating
Configuration files support Go template syntax for environment variables:
persistence :
datastores :
default :
sql :
connectAddr : "{{ env \" MYSQL_HOST \" }}:{{ default \" 3306 \" (env \" MYSQL_PORT \" ) }}"
user : "{{ env \" MYSQL_USER \" }}"
password : "{{ env \" MYSQL_PASSWORD \" }}"
Template functions:
env "VAR" - Get environment variable
default "value" (env "VAR") - Get with default
coalesce (env "VAR1") (env "VAR2") "default" - First non-empty value
Complete Example
View complete production configuration
log :
stdout : true
level : info
persistence :
numHistoryShards : 512
defaultStore : mysql-default
visibilityStore : es-visibility
datastores :
mysql-default :
sql :
pluginName : "mysql8"
databaseName : "temporal"
connectAddr : "mysql.example.com:3306"
connectProtocol : "tcp"
user : "temporal"
password : "${MYSQL_PASSWORD}"
maxConns : 50
maxIdleConns : 25
maxConnLifetime : "30m"
tls :
enabled : true
caFile : "/etc/temporal/certs/mysql-ca.pem"
enableHostVerification : true
serverName : "mysql.example.com"
es-visibility :
elasticsearch :
version : "v7"
logLevel : "error"
url :
scheme : "https"
host : "elasticsearch.example.com:9200"
username : "elastic"
password : "${ES_PASSWORD}"
indices :
visibility : "temporal_visibility_v1_prod"
closeIdleConnectionsInterval : "15s"
global :
membership :
maxJoinDuration : 30s
broadcastAddress : ""
pprof :
port : 0
metrics :
prometheus :
framework : "opentelemetry"
timerType : "histogram"
listenAddress : "0.0.0.0:8000"
tls :
refreshInterval : "1h"
expirationChecks :
warningWindow : "720h"
errorWindow : "168h"
checkInterval : "24h"
internode :
server :
requireClientAuth : true
certFile : "/etc/temporal/certs/server-cert.pem"
keyFile : "/etc/temporal/certs/server-key.pem"
clientCaFiles :
- "/etc/temporal/certs/ca-cert.pem"
client :
serverName : "temporal-server"
disableHostVerification : false
rootCaFiles :
- "/etc/temporal/certs/ca-cert.pem"
frontend :
server :
requireClientAuth : true
certFile : "/etc/temporal/certs/frontend-cert.pem"
keyFile : "/etc/temporal/certs/frontend-key.pem"
clientCaFiles :
- "/etc/temporal/certs/client-ca-cert.pem"
client :
serverName : "temporal.example.com"
disableHostVerification : false
rootCaFiles :
- "/etc/temporal/certs/ca-cert.pem"
authorization :
jwtKeyProvider :
keySourceURIs :
- "https://auth.example.com/.well-known/jwks.json"
refreshInterval : "1m"
permissionsClaimName : "permissions"
services :
frontend :
rpc :
grpcPort : 7233
membershipPort : 6933
bindOnIP : "0.0.0.0"
httpPort : 7243
history :
rpc :
grpcPort : 7234
membershipPort : 6934
bindOnIP : "0.0.0.0"
matching :
rpc :
grpcPort : 7235
membershipPort : 6935
bindOnIP : "0.0.0.0"
worker :
rpc :
grpcPort : 7239
membershipPort : 6939
bindOnIP : "0.0.0.0"
clusterMetadata :
enableGlobalNamespace : false
failoverVersionIncrement : 10
masterClusterName : "active"
currentClusterName : "active"
clusterInformation :
active :
enabled : true
initialFailoverVersion : 1
rpcName : "frontend"
rpcAddress : "temporal.example.com:7233"
httpAddress : "temporal.example.com:7243"
dcRedirectionPolicy :
policy : "noop"
archival :
history :
state : "enabled"
enableRead : true
provider :
s3store :
region : "us-east-1"
visibility :
state : "enabled"
enableRead : true
provider :
s3store :
region : "us-east-1"
namespaceDefaults :
archival :
history :
state : "disabled"
URI : "s3://temporal-archival-prod/history"
visibility :
state : "disabled"
URI : "s3://temporal-archival-prod/visibility"
dynamicConfigClient :
filepath : "/etc/temporal/config/dynamicconfig/production.yaml"
pollInterval : "60s"
Validation
Validate your configuration before deployment:
# Dry run to check configuration
temporal-server --config /etc/temporal/config/production.yaml start --dry-run
# Check for common issues
temporal-server --config /etc/temporal/config/production.yaml validate