Skip to main content

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
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