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.
This guide covers deploying Temporal Server using Docker, from local development setups to production-ready containerized deployments.
Quick Start
The fastest way to get Temporal running locally:
brew install temporal
temporal server start-dev
This starts a server with in-memory SQLite storage suitable for development.
Docker Image
Temporal provides official Docker images:
docker pull temporalio/server:latest
Image Details
The server image is based on Alpine Linux and includes:
temporal-server binary in /usr/local/bin/
Entrypoint script at /etc/temporal/entrypoint.sh
Non-root user temporal (UID 1000, GID 1000)
Docker Compose Setup
Development Environment
For local development with all dependencies:
Create docker-compose.yml
services :
mysql :
image : mysql:8.0.29-oracle
container_name : temporal-mysql
ports :
- "3306:3306"
environment :
MYSQL_ROOT_PASSWORD : root
volumes :
- ./mysql-init:/docker-entrypoint-initdb.d
networks :
- temporal-network
elasticsearch :
image : elasticsearch:7.10.1
container_name : temporal-elasticsearch
ports :
- "9200:9200"
environment :
- discovery.type=single-node
- ES_JAVA_OPTS=-Xms100m -Xmx100m
networks :
- temporal-network
temporal :
image : temporalio/server:latest
container_name : temporal-server
depends_on :
- mysql
ports :
- "7233:7233"
- "7243:7243"
- "8000:8000"
environment :
- DB=mysql8
- MYSQL_SEEDS=mysql
- MYSQL_USER=temporal
- MYSQL_PWD=temporal
- ENABLE_ES=false
- DYNAMIC_CONFIG_FILE_PATH=/etc/temporal/config/dynamicconfig/docker.yaml
volumes :
- ./config:/etc/temporal/config
networks :
- temporal-network
temporal-ui :
image : temporalio/ui:latest
container_name : temporal-ui
depends_on :
- temporal
ports :
- "8233:8080"
environment :
- TEMPORAL_ADDRESS=temporal:7233
networks :
- temporal-network
networks :
temporal-network :
driver : bridge
Create MySQL initialization script
CREATE USER ' temporal '@ '%' IDENTIFIED BY 'temporal' ;
GRANT ALL PRIVILEGES ON * . * TO 'temporal' @ '%' ;
FLUSH PRIVILEGES;
Initialize database schema
# Create databases
docker exec temporal-server temporal-sql-tool \
--ep mysql --port 3306 \
--user temporal --password temporal \
--db temporal --plugin mysql8 create
docker exec temporal-server temporal-sql-tool \
--ep mysql --port 3306 \
--user temporal --password temporal \
--db temporal_visibility --plugin mysql8 create
# Setup schema
docker exec temporal-server temporal-sql-tool \
--ep mysql --port 3306 \
--user temporal --password temporal \
--db temporal --plugin mysql8 \
setup-schema -v 0.0
docker exec temporal-server temporal-sql-tool \
--ep mysql --port 3306 \
--user temporal --password temporal \
--db temporal --plugin mysql8 \
update-schema --schema-name mysql/v8/temporal
# Repeat for visibility
docker exec temporal-server temporal-sql-tool \
--ep mysql --port 3306 \
--user temporal --password temporal \
--db temporal_visibility --plugin mysql8 \
setup-schema -v 0.0
docker exec temporal-server temporal-sql-tool \
--ep mysql --port 3306 \
--user temporal --password temporal \
--db temporal_visibility --plugin mysql8 \
update-schema --schema-name mysql/v8/visibility
Access the UI
Open http://localhost:8233 to access Temporal Web UI.
Environment Variables
The Docker image supports configuration via environment variables:
Database Configuration
MySQL
PostgreSQL
Cassandra
DB = mysql8
MYSQL_SEEDS = mysql-host
MYSQL_USER = temporal
MYSQL_PWD = temporal
DB_PORT = 3306
DBNAME = temporal
VISIBILITY_DBNAME = temporal_visibility
# Connection pool
SQL_MAX_CONNS = 20
SQL_MAX_IDLE_CONNS = 20
SQL_MAX_CONN_TIME = 1h
# TLS (optional)
SQL_TLS_ENABLED = false
SQL_CA = /path/to/ca.pem
SQL_CERT = /path/to/cert.pem
SQL_CERT_KEY = /path/to/key.pem
DB = postgres12
POSTGRES_SEEDS = postgres-host
POSTGRES_USER = temporal
POSTGRES_PWD = temporal
DB_PORT = 5432
DBNAME = temporal
VISIBILITY_DBNAME = temporal_visibility
# Connection pool
SQL_MAX_CONNS = 20
SQL_MAX_IDLE_CONNS = 20
SQL_MAX_CONN_TIME = 1h
DB = cassandra
CASSANDRA_SEEDS = cassandra-host
CASSANDRA_PORT = 9042
KEYSPACE = temporal
CASSANDRA_USER = cassandra
CASSANDRA_PASSWORD = cassandra
# Connection pool
CASSANDRA_MAX_CONNS = 20
# TLS (optional)
CASSANDRA_TLS_ENABLED = false
CASSANDRA_CA = /path/to/ca.pem
Elasticsearch Configuration
ENABLE_ES = true
ES_VERSION = v7
ES_SCHEME = http
ES_SEEDS = elasticsearch-host
ES_PORT = 9200
ES_USER = elastic
ES_PWD = changeme
ES_VIS_INDEX = temporal_visibility_v1_dev
Service Configuration
# History shards
NUM_HISTORY_SHARDS = 4
# Service ports
FRONTEND_GRPC_PORT = 7233
FRONTEND_HTTP_PORT = 7243
FRONTEND_MEMBERSHIP_PORT = 6933
HISTORY_GRPC_PORT = 7234
HISTORY_MEMBERSHIP_PORT = 6934
MATCHING_GRPC_PORT = 7235
MATCHING_MEMBERSHIP_PORT = 6935
WORKER_GRPC_PORT = 7239
WORKER_MEMBERSHIP_PORT = 6939
# Bind address
BIND_ON_IP = 0.0.0.0
TEMPORAL_BROADCAST_ADDRESS =
Logging and Metrics
# Logging
LOG_LEVEL = info
# Prometheus metrics
PROMETHEUS_ENDPOINT = 0.0.0.0:8000
PROMETHEUS_TIMER_TYPE = histogram
# Or StatsD metrics
STATSD_ENDPOINT = statsd-host:8125
# Profiling
PPROF_PORT = 7936
TLS Configuration
# Internode TLS
TEMPORAL_TLS_REQUIRE_CLIENT_AUTH = true
TEMPORAL_TLS_SERVER_CERT = /certs/server-cert.pem
TEMPORAL_TLS_SERVER_KEY = /certs/server-key.pem
TEMPORAL_TLS_SERVER_CA_CERT = /certs/ca-cert.pem
TEMPORAL_TLS_INTERNODE_SERVER_NAME = temporal-server
# Frontend TLS
TEMPORAL_TLS_FRONTEND_CERT = /certs/frontend-cert.pem
TEMPORAL_TLS_FRONTEND_KEY = /certs/frontend-key.pem
TEMPORAL_TLS_CLIENT1_CA_CERT = /certs/client-ca-cert.pem
TEMPORAL_TLS_FRONTEND_SERVER_NAME = temporal-frontend
Production Deployment
Multi-Container Setup
For production, run separate containers for each service:
docker-compose-production.yml
services :
temporal-frontend :
image : temporalio/server:latest
command :
- /usr/local/bin/temporal-server
- start
- --service
- frontend
environment :
- SERVICES=frontend
deploy :
replicas : 2
resources :
limits :
cpus : '2'
memory : 4G
networks :
- temporal-network
temporal-history :
image : temporalio/server:latest
command :
- /usr/local/bin/temporal-server
- start
- --service
- history
environment :
- SERVICES=history
- NUM_HISTORY_SHARDS=512
deploy :
replicas : 3
resources :
limits :
cpus : '4'
memory : 8G
networks :
- temporal-network
temporal-matching :
image : temporalio/server:latest
command :
- /usr/local/bin/temporal-server
- start
- --service
- matching
environment :
- SERVICES=matching
deploy :
replicas : 2
resources :
limits :
cpus : '2'
memory : 4G
networks :
- temporal-network
temporal-worker :
image : temporalio/server:latest
command :
- /usr/local/bin/temporal-server
- start
- --service
- worker
environment :
- SERVICES=worker
deploy :
replicas : 1
resources :
limits :
cpus : '2'
memory : 4G
networks :
- temporal-network
networks :
temporal-network :
driver : overlay
Health Checks
Add health checks to your containers:
healthcheck :
test : [ "CMD" , "/usr/local/bin/temporal-server" , "health" ]
interval : 30s
timeout : 10s
retries : 3
start_period : 40s
Volume Mounts
Mount configuration and TLS certificates:
volumes :
- ./config/production.yaml:/etc/temporal/config/config.yaml:ro
- ./certs:/etc/temporal/certs:ro
- ./dynamicconfig:/etc/temporal/config/dynamicconfig:ro
Dockerfile Reference
The official Temporal Server Dockerfile:
ARG ALPINE_TAG=3.23.3
FROM alpine:${ALPINE_TAG}
ARG TARGETARCH
RUN apk add --no-cache \
ca-certificates \
tzdata && addgroup -g 1000 temporal && \
adduser -u 1000 -G temporal -D temporal
COPY --chmod=755 ./build/${TARGETARCH}/temporal-server /usr/local/bin/
COPY --chmod=755 ./scripts/sh/entrypoint.sh /etc/temporal/entrypoint.sh
WORKDIR /etc/temporal
USER temporal
CMD [ "/etc/temporal/entrypoint.sh" ]
Entrypoint Script
#!/bin/sh
set -eu -o pipefail
# Resolve hostname to IP address if not already set
: "${ BIND_ON_IP := $( getent hosts "$( hostname )" | awk '{print $1;}')}"
export BIND_ON_IP
# Set broadcast address for wildcard binds
if [ "${ BIND_ON_IP }" = "0.0.0.0" ] || [ "${ BIND_ON_IP }" = "::0" ]; then
: "${ TEMPORAL_BROADCAST_ADDRESS := $( getent hosts "$( hostname )" | awk '{print $1;}')}"
export TEMPORAL_BROADCAST_ADDRESS
fi
exec temporal-server start
Common Issues
Database connection errors
Symptoms : Container fails to start with database connection errorsSolutions :
Ensure database is running and accessible
Verify network connectivity between containers
Check database credentials in environment variables
Initialize schema using temporal-sql-tool or temporal-cassandra-tool
Symptoms : “Address already in use” errorsSolutions :
Check for other services using the same ports
Modify port mappings in docker-compose.yml
Use environment variables to change default ports
Symptoms : Container OOM killed or high CPU usageSolutions :
Increase Docker memory limits
Reduce NUM_HISTORY_SHARDS for development
Lower database connection pool sizes
Scale services horizontally