Skip to main content
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
stdout
boolean
default:"true"
Output logs to stdout instead of files
level
string
default:"info"
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
numHistoryShards
integer
default:"4"
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

maxConns
integer
default:"20"
Maximum number of connections to the database
maxIdleConns
integer
default:"20"
Maximum number of idle connections to maintain
maxConnLifetime
duration
default:"1h"
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"
maxJoinDuration
duration
default:"30s"
Maximum time for a service to join the cluster ring
broadcastAddress
string
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

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

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)

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.

Cluster Metadata

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"
enableGlobalNamespace
boolean
default:"false"
Enable global namespaces for multi-cluster replication
failoverVersionIncrement
integer
default:"10"
Version increment between clusters. Use larger values (100+) for multi-cluster.

Archival Configuration

Archive completed workflow histories for long-term 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"

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

config/production.yaml
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

Build docs developers (and LLMs) love