Documentation Index Fetch the complete documentation index at: https://mintlify.com/temporalio/temporal/llms.txt
Use this file to discover all available pages before exploring further.
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