ScyllaDB University LIVE, FREE Virtual Training Event | March 21
Register for Free
ScyllaDB Documentation Logo Documentation
  • Deployments
    • Cloud
    • Server
  • Tools
    • ScyllaDB Manager
    • ScyllaDB Monitoring Stack
    • ScyllaDB Operator
  • Drivers
    • CQL Drivers
    • DynamoDB Drivers
    • Supported Driver Versions
  • Resources
    • ScyllaDB University
    • Community Forum
    • Tutorials
Install
Search Ask AI
ScyllaDB Docs ScyllaDB Documentation Get Started with ScyllaDB Build with AI AI Integrations Temporal
For AI agents: a documentation index is available at https://docs.scylladb.com/main/llms.txt. A Markdown version of this page is at https://docs.scylladb.com/main/get-started/build-with-ai/integrations/temporal.md.

Temporal¶

Temporal logo

Temporal is a durable execution platform: it runs your application’s Workflows and Activities in a way that survives process crashes, network failures, and timeouts, automatically retrying and resuming from the last completed step.

The Temporal Server persists all Workflow, Activity, and history state through a pluggable persistence layer.

Two back-end store elements¶

Starting from Temporal v1.24.0 release notes, back-end is split into two elements:

  • Execution store (Workflow/Activity/history state)

  • Visibility store

Scope of this page is the first, Execution store.

Prerequisites¶

  • Docker Compose

  • A self-hosted ScyllaDB cluster or a ScyllaDB Cloud cluster

Self-hosted ScyllaDB¶

The following docker-compose.yml starts ScyllaDB, Elasticsearch, and the official Temporal Server image configured to use the Cassandra plugin against ScyllaDB.

Create a temporal-config directory next to your docker-compose.yml and fetch the upstream config template into it:

mkdir -p temporal-config/config temporal-config/dynamicconfig
curl -sL -o temporal-config/config/docker.yaml \
  https://raw.githubusercontent.com/temporalio/temporal/v1.32.0/config/docker.yaml
touch temporal-config/dynamicconfig/docker.yaml

The first command downloads the base server config template that the temporal container renders at startup. The second creates an empty dynamic-config file — the template references it by default, and the file just needs to exist; you can add dynamic config settings to it later.

services:
  scylladb:
    image: scylladb/scylla:2026.3
    command: >-
      --smp 1 --memory 1G --overprovisioned 1 --api-address 0.0.0.0
    ports:
      - "9042:9042"
    healthcheck:
      test: ["CMD-SHELL", "cqlsh -e 'describe keyspaces'"]
      interval: 5s
      timeout: 5s
      retries: 60
      start_period: 30s

  elasticsearch:
    image: elasticsearch:8.19.21
    environment:
      - discovery.type=single-node
      - xpack.security.enabled=false
      - ES_JAVA_OPTS=-Xms256m -Xmx256m
    ports:
      - "9200:9200"
    healthcheck:
      test: ["CMD-SHELL", "curl -sf 'http://localhost:9200/_cluster/health?wait_for_status=yellow&timeout=1s' || exit 1"]
      interval: 5s
      timeout: 5s
      retries: 60
      start_period: 30s

  temporal-admin-tools:
    image: temporalio/admin-tools:1.32.0
    depends_on:
      scylladb:
        condition: service_healthy
      elasticsearch:
        condition: service_healthy
    environment:
      - CASSANDRA_SEEDS=scylladb
      - ES_HOST=elasticsearch
      - ES_PORT=9200
      - ES_SCHEME=http
      - ES_VERSION=v8
      - ES_VISIBILITY_INDEX=temporal_visibility_v1_dev
    entrypoint: ["/bin/sh", "-c"]
    command: >
      "temporal-cassandra-tool --ep scylladb create -k temporal --rf 1 --datacenter datacenter1 &&
       temporal-cassandra-tool --ep scylladb -k temporal setup-schema -v 0.0 &&
       temporal-cassandra-tool --ep scylladb -k temporal update-schema -d /etc/temporal/schema/cassandra/temporal/versioned &&
       temporal-elasticsearch-tool --ep http://elasticsearch:9200 setup-schema &&
       temporal-elasticsearch-tool --ep http://elasticsearch:9200 create-index --index temporal_visibility_v1_dev"

  temporal:
    image: temporalio/server:1.32.0
    depends_on:
      temporal-admin-tools:
        condition: service_completed_successfully
    environment:
      - DB=cassandra
      - CASSANDRA_SEEDS=scylladb
      - KEYSPACE=temporal
      - ENABLE_ES=true
      - ES_SEEDS=elasticsearch
      - ES_VERSION=v8
      - ES_VISIBILITY_INDEX=temporal_visibility_v1_dev
      - BIND_ON_IP=0.0.0.0
      - TEMPORAL_BROADCAST_ADDRESS=0.0.0.0
    volumes:
      - ./temporal-config/config/docker.yaml:/etc/temporal/config/docker.yaml:ro
      - ./temporal-config/dynamicconfig:/etc/temporal/config/dynamicconfig:ro
    entrypoint: ["temporal-server", "--root", "/etc/temporal", "--env", "docker", "start"]
    ports:
      - "7233:7233"

  temporal-ui:
    image: temporalio/ui:2.54.1
    depends_on:
      - temporal
    environment:
      - TEMPORAL_ADDRESS=temporal:7233
    ports:
      - "8080:8080"

Note

By default, temporal-cassandra-tool create builds its temporal keyspace with SimpleStrategy, which isn’t recommended for ScyllaDB. Passing --datacenter datacenter1 (as in the command above) makes the tool use NetworkTopologyStrategy instead.

On first startup, temporal-admin-tools creates the temporal keyspace in ScyllaDB and the temporal_visibility_v1_dev index in Elasticsearch, then exits; the temporal service only starts once that container completes successfully. Start the stack with:

docker compose up -d

Temporal is now listening on localhost:7233, and the Web UI is at http://localhost:8080.

ScyllaDB Cloud¶

When using ScyllaDB Cloud as the execution store, run the Temporal Server on your own infrastructure and point it at your cluster’s contact points. Find them on the Connect tab of your cluster in the ScyllaDB Cloud Console.

As with the self-hosted setup, temporalio/server needs a rendered config mounted into the container. Fetch the same upstream template:

mkdir -p temporal-config/config temporal-config/dynamicconfig
curl -sL -o temporal-config/config/docker.yaml \
  https://raw.githubusercontent.com/temporalio/temporal/v1.32.0/config/docker.yaml
touch temporal-config/dynamicconfig/docker.yaml

Before starting temporal-server, you still need to create the keyspace and stand up Elasticsearch, covered next.

Creating the keyspace¶

On ScyllaDB Cloud you must provide the keyspace yourself rather than let Temporal create it. Pre-create it once from a CQL client (for example cqlsh):

docker run --rm -it scylladb/scylla-cqlsh \
  node-0.your-cluster.datacenter.clusters.scylla.cloud 9042 \
  -u "<your-username>" -p "<your-password>"
CREATE KEYSPACE temporal
WITH replication = {'class': 'NetworkTopologyStrategy', 'replication_factor': 3};

Then load Temporal’s schema into the keyspace yourself with the temporal-cassandra-tool (it ships inside the temporalio/admin-tools image). Run setup-schema followed by update-schema:

docker run --rm --entrypoint temporal-cassandra-tool \
  temporalio/admin-tools:1.32.0 \
  --endpoint node-0.your-cluster.datacenter.clusters.scylla.cloud \
  --user "<your-username>" --password "<your-password>" \
  --keyspace temporal --datacenter <your-datacenter> \
  --disable-initial-host-lookup \
  setup-schema -v 0.0

docker run --rm --entrypoint temporal-cassandra-tool \
  temporalio/admin-tools:1.32.0 \
  --endpoint node-0.your-cluster.datacenter.clusters.scylla.cloud \
  --user "<your-username>" --password "<your-password>" \
  --keyspace temporal --datacenter <your-datacenter> \
  --disable-initial-host-lookup \
  update-schema -d /etc/temporal/schema/cassandra/temporal/versioned

Creating the Elasticsearch visibility index¶

Start Elasticsearch:

docker run -d --name elasticsearch -p 9200:9200 \
  -e discovery.type=single-node \
  -e xpack.security.enabled=false \
  -e ES_JAVA_OPTS="-Xms256m -Xmx256m" \
  elasticsearch:8.19.21

Then, before starting temporal-server, load Temporal’s index template into it:

docker run --rm --entrypoint temporal-elasticsearch-tool \
  temporalio/admin-tools:1.32.0 \
  --ep http://host.docker.internal:9200 \
  setup-schema

docker run --rm --entrypoint temporal-elasticsearch-tool \
  temporalio/admin-tools:1.32.0 \
  --ep http://host.docker.internal:9200 \
  create-index --index temporal_visibility_v1_dev

Starting the server¶

With the keyspace and Elasticsearch index in place, start temporal-server, setting ES_SEEDS to the Elasticsearch instance you just created:

docker run -p 7233:7233 \
  -e DB=cassandra \
  -e CASSANDRA_SEEDS="node-0.your-cluster.datacenter.clusters.scylla.cloud,node-1.your-cluster.datacenter.clusters.scylla.cloud,node-2.your-cluster.datacenter.clusters.scylla.cloud" \
  -e CASSANDRA_USER="<your-username>" \
  -e CASSANDRA_PASSWORD="<your-password>" \
  -e KEYSPACE=temporal \
  -e ENABLE_ES=true \
  -e ES_SEEDS=host.docker.internal \
  -e ES_VERSION=v8 \
  -e BIND_ON_IP=0.0.0.0 \
  -e TEMPORAL_BROADCAST_ADDRESS=0.0.0.0 \
  -v "$(pwd)/temporal-config/config/docker.yaml:/etc/temporal/config/docker.yaml:ro" \
  -v "$(pwd)/temporal-config/dynamicconfig:/etc/temporal/config/dynamicconfig:ro" \
  --entrypoint temporal-server \
  temporalio/server:1.32.0 \
  --root /etc/temporal --env docker start

Application data alongside Temporal¶

Temporal’s own temporal keyspace (Workflow/Activity/history state) and your application’s business-data keyspace can live on the same ScyllaDB cluster as long as they use separate keyspaces. A worker process can use the scylla-driver (a drop-in-compatible fork of cassandra-driver) to read/write its own tables from Activities, independent of Temporal’s persistence.

Create the application keyspace and table once, before your Activities start using them:

import os
from cassandra.cluster import Cluster

cluster = Cluster(os.environ["SCYLLA_HOSTS"].split(","))
session = cluster.connect()

session.execute(
    """
    CREATE KEYSPACE IF NOT EXISTS orders_app
    WITH replication = {'class': 'NetworkTopologyStrategy', 'replication_factor': 1}
    """
)
session.set_keyspace("orders_app")
session.execute(
    """
    CREATE TABLE IF NOT EXISTS orders (
        order_id text PRIMARY KEY,
        status text
    )
    """
)

Then read/write from your Activities as usual:

session.execute(
    "INSERT INTO orders (order_id, status) VALUES (%s, %s)",
    (order_id, "received"),
)

This keeps application state fully separate from Temporal’s internal schema while sharing the same cluster.

Additional Resources¶

  • ScyllaDB Cloud docs

  • Temporal Server repository

  • Temporal documentation

  • Temporal persistence configuration reference

  • Building High Availability for Temporal Workflows — ShareChat Engineering

Was this page helpful?

PREVIOUS
Resonate
NEXT
ScyllaDB Drivers
  • Create an issue
  • Edit this page

On this page

  • Temporal
    • Two back-end store elements
    • Prerequisites
    • Self-hosted ScyllaDB
    • ScyllaDB Cloud
      • Creating the keyspace
      • Creating the Elasticsearch visibility index
      • Starting the server
    • Application data alongside Temporal
    • Additional Resources
ScyllaDB Documentation
Search Ask AI
  • Get Started with ScyllaDB
    • New to ScyllaDB? Start here!
    • Develop with ScyllaDB
      • Run ScyllaDB
      • Install a Driver
      • Connect an Application
      • Tutorials and Example Projects
    • Query Data
      • CQL
      • Schema
      • Inserting Data
      • Reading Data
      • Updating Data
      • Deleting Data
    • Data Modeling
      • Query Design
      • Schema Design
      • Data Modeling Best Practices
    • Learn to Use ScyllaDB
    • Build with AI
      • ScyllaDB Agent Skills
      • AI Integrations
        • MCP Toolbox for Databases
        • LangGraph
        • Feast
        • Resonate
        • Temporal
  • ScyllaDB Drivers
    • ScyllaDB CQL Drivers
    • ScyllaDB DynamoDB Drivers
    • Third-party Drivers
  • Versioning and Support Policy
    • ScyllaDB Version Support
    • Driver Support
    • OS Support per ScyllaDB Version
    • Upgrade Policy
Docs Tutorials University Contact Us About Us
© 2026, ScyllaDB. All rights reserved. | Terms of Service | Privacy Policy | ScyllaDB, and ScyllaDB Cloud, are registered trademarks of ScyllaDB, Inc.
Last updated on 16 Sep 2026.
Powered by Sphinx 9.1.0 & ScyllaDB Theme 1.9.3