> ## Documentation Index
> Fetch the complete documentation index at: https://docs.controlplane.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Temporal

> Deploy Temporal on Control Plane using the Template Catalog. Durable-execution platform for workflows that survive crashes and restarts, backed by a highly available PostgreSQL cluster. Covers worker connections, database modes, the permanent history-shard count, and the internal-only Web UI.

## Overview

Temporal is an open-source (MIT) durable-execution platform — applications write workflows as ordinary code, and the Temporal server guarantees they run to completion, surviving process crashes, restarts, and long waits. This template deploys a single-process Temporal server exposing the gRPC frontend to your workloads, plus the Temporal Web UI, both internal-only, backed by a highly available PostgreSQL cluster by default. Database and schema setup run automatically at boot, including schema migrations on version upgrades.

### Architecture

* **Temporal server** — A single-replica standard workload running all four Temporal services (frontend, history, matching, worker) in one process; gRPC frontend on port `7233`, internal-only. Stateless by design: all workflow state lives in PostgreSQL.
* **Temporal Web UI** *(optional, default on)* — A standard workload serving the UI on port `8080`, internal-only (the UI has no built-in authentication).
* **PostgreSQL (HA, default)** — The [postgres-highly-available](/template-catalog/templates/postgres-highly-available) template as a subchart: 3× Patroni PostgreSQL, 3× etcd, and a HAProxy leader-routing endpoint Temporal connects through.
* **PostgreSQL (dev/lightweight, optional)** — The single-instance [postgres](/template-catalog/templates/postgres) template instead, for lighter non-HA deployments.

### What Gets Created

* **Standard Temporal Server Workload** — A single replica running all four Temporal services in one process, serving gRPC on port `7233`. No volume set — all state lives in the database.
* **Standard Temporal UI Workload** *(optional)* — The Temporal Web UI on port `8080`.
* **Database Workloads** — HA mode: a stateful Patroni PostgreSQL workload, a stateful etcd workload, and a standard HAProxy leader-routing workload. Single mode: one stateful PostgreSQL workload.
* **Volume Sets** — The database subchart's persistent volumes (10 GiB per replica by default). Temporal itself has none.
* **Secrets** — The database credentials from the subchart.
* **Identity & Policy** — A least-privilege policy granting the server identity `reveal` on exactly the database credentials secret. The UI workload has no identity — it mounts no secrets.
* **Cron Backup Workload** *(optional)* — When database backups are enabled.

<Note>
  This template does not create a GVC. You must deploy it into an existing GVC.
</Note>

## Prerequisites

None for a default install. For optional database backups, you need a bucket and access setup for one of the supported providers — see [Backing Up](#backing-up).

Install the template using your preferred method:

<CardGroup cols={2}>
  <Card title="UI" href="/template-catalog/install-manage/ui" icon="laptop">
    Browse, install, and manage templates visually
  </Card>

  <Card title="CLI" href="/template-catalog/install-manage/cli" icon="terminal">
    Manage templates from your terminal
  </Card>

  <Card title="Terraform" href="/template-catalog/install-manage/terraform" icon={<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><g fill-rule="evenodd"><path d="M77.941 44.5v36.836L46.324 62.918V26.082zm0 0" fill="#5c4ee5"/><path d="M81.41 81.336l31.633-18.418V26.082L81.41 44.5zm0 0" fill="#4040b2"/><path d="M11.242 42.36L42.86 60.776V23.941L11.242 5.523zm0 0M77.941 85.375L46.324 66.957v36.82l31.617 18.418zm0 0" fill="#5c4ee5"/></g></svg>}>
    Declare templates in your Terraform configurations
  </Card>

  <Card
    title="Pulumi"
    href="/template-catalog/install-manage/pulumi"
    icon={<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" id="Pulumi-Icon--Streamline-Svg-Logos" height="24" width="24">
    <desc>
        Pulumi Icon Streamline Icon: https://streamlinehq.com
    </desc>
    <path fill="#f26e7e" d="M4.683025 13.3318c0.869125 -0.5018 0.870575 -2.1264 0.003225 -3.62865s-2.27504 -2.313275 -3.1441725 -1.811475C0.672945 8.3935 0.6715 10.0181 1.53885 11.52035c0.86735 1.502275 2.27505 2.313275 3.144175 1.81145Zm0.0052 3.2167c0.86735 1.502275 0.865925 3.126875 -0.003225 3.628675 -0.86915 0.5018 -2.2768275 -0.309225 -3.144175 -1.81145 -0.8673525 -1.50225 -0.8659075 -3.126875 0.003225 -3.628675 0.8691325 -0.5018 2.276825 0.309225 3.144175 1.81145Zm5.922875 3.4243c0.86735 1.50225 0.8659 3.126775 -0.003225 3.62875 -0.869125 0.501775 -2.27685 -0.309325 -3.1442 -1.81155 -0.867325 -1.50225 -0.865875 -3.12685 0.00325 -3.628675 0.869125 -0.5018 2.276825 0.309225 3.144175 1.811475Zm-0.001925 -6.845275c0.86735 1.50225 0.8659 3.12685 -0.003225 3.628675 -0.869125 0.5018 -2.276825 -0.309225 -3.144175 -1.811475 -0.86735 -1.50225 -0.8659 -3.12685 0.003225 -3.62865 0.869125 -0.501825 2.276825 0.3092 3.144175 1.81145Z" stroke-width="0.25"></path>
    <path fill="#8a3391" d="M22.45775 11.524125c0.86725 -1.502225 0.865925 -3.12685 -0.003225 -3.62865 -0.869125 -0.501825 -2.276825 0.3092 -3.144175 1.811475 -0.86735 1.50225 -0.8659 3.126825 0.003225 3.62865 0.869125 0.501825 2.276825 -0.3092 3.144175 -1.811475Zm0.000175 3.2151c0.869075 0.5018 0.870625 2.1264 0.003225 3.62865 -0.86735 1.50225 -2.27505 2.313275 -3.144175 1.81145 -0.869125 -0.5018 -0.870575 -2.126425 -0.003225 -3.62865 0.86735 -1.50225 2.27505 -2.313275 3.144175 -1.81145ZM16.536225 18.157875c0.86915 0.501825 0.8706 2.126425 0.00325 3.628675 -0.86735 1.502125 -2.275075 2.313225 -3.1442 1.81145 -0.869125 -0.50175 -0.870575 -2.126425 -0.003225 -3.62865 0.867375 -1.502275 2.27505 -2.3133 3.144175 -1.811475Zm-0.003325 -6.843775c0.869125 0.5018 0.870575 2.126425 0.003225 3.628675s-2.27505 2.313275 -3.1442 1.811475c-0.869125 -0.501825 -0.870575 -2.126425 -0.003225 -3.628675 0.86735 -1.502275 2.27505 -2.313275 3.1442 -1.811475Z" stroke-width="0.25"></path>
    <path fill="#f7bf2a" d="M15.138225 2.06721c0 1.003615 -1.40625 1.817215 -3.14095 1.817215 -1.7347 0 -3.14095 -0.8136 -3.14095 -1.817215C8.856325 1.06359 10.262575 0.25 11.997275 0.25c1.7347 0 3.14095 0.81359 3.14095 1.81721ZM9.2166 5.482375c0 1.003625 -1.40625 1.8172 -3.14095 1.8172 -1.7347 0 -3.14095 -0.813575 -3.14095 -1.8172s1.40625 -1.817225 3.14095 -1.817225c1.7347 0 3.14095 0.8136 3.14095 1.817225Zm8.71005 1.8172c1.7347 0 3.14095 -0.813575 3.14095 -1.8172s-1.40625 -1.817225 -3.14095 -1.817225c-1.7347 0 -3.14095 0.8136 -3.14095 1.817225s1.40625 1.8172 3.14095 1.8172Zm-2.788425 1.605625c0 1.003625 -1.40625 1.8172 -3.14095 1.8172 -1.7347 0 -3.14095 -0.813575 -3.14095 -1.8172 0 -1.0036 1.40625 -1.8172 3.14095 -1.8172 1.7347 0 3.14095 0.8136 3.14095 1.8172Z" stroke-width="0.25"></path>
    </svg>}
  >
    Declare templates in your Pulumi programs
  </Card>
</CardGroup>

## Choosing a Database Mode

Exactly one of the two database modes must be enabled — the chart enforces this at render and fails the install with a clear message otherwise.

|                   | `postgresHA` (default)                                          | `postgres`                             |
| ----------------- | --------------------------------------------------------------- | -------------------------------------- |
| What runs         | 3× Patroni PostgreSQL, 3× etcd, HAProxy leader endpoint         | One single-replica PostgreSQL workload |
| Database failover | Automatic (Patroni leader election)                             | None                                   |
| Footprint         | 8 replicas across 3 workloads (3× Patroni, 3× etcd, 2× HAProxy) | 1 workload                             |
| Best for          | Production                                                      | Development and lightweight installs   |

A fresh HA-mode install converges in roughly 4–6 minutes — the server waits for the database, then runs full schema setup before it starts listening. Single mode is ready in under 3 minutes.

## Configuration

The default `values.yaml` for this template:

```yaml theme={null}
image: temporalio/auto-setup:1.29.7 # Temporal server + schema tools; boot runs schema setup, then the server

resources:
  cpu: 1000m
  memory: 2Gi
  minCpu: 500m
  minMemory: 1Gi

historyShards: 512 # PERMANENT after first install — cannot ever be changed for this cluster
namespaceRetention: 72h # how long closed workflow histories are kept in the default namespace

ui: # internal-only: the Temporal UI has no built-in authentication
  enabled: true
  image: temporalio/ui:2.52.1
  resources:
    cpu: 500m
    memory: 512Mi
    minCpu: 125m
    minMemory: 128Mi

internalAccess: # internal firewall scope for the gRPC frontend (:7233) and the UI (:8080)
  type: same-gvc # options: none, same-gvc, same-org, workload-list
  workloads: [] # used with workload-list, e.g. //gvc/GVC_NAME/workload/WORKLOAD_NAME

postgresHA: # default: highly available PostgreSQL
  enabled: true
  postgres:
    username: temporal
    password: change-me-temporal-db-password # change before installing
    database: temporal
  replicas: 3
  volumeset:
    capacity: 10 # initial capacity in GiB per replica (minimum is 10)
  backup:
    enabled: false # optional — see Backing Up
    mode: logical # logical or wal-g
    resources:
      cpu: 100m
      memory: 128Mi
    logical:
      image: ghcr.io/controlplane-com/backup-images/postgres-backup:17.1.0
      schedule: "0 2 * * *"
    walg:
      intervalSeconds: 21600
    provider: aws # options: aws, gcp, minio
    aws:
      bucket: temporal-pg-backup-bucket
      region: us-east-1
      cloudAccountName: my-s3-cloud-account
      policyName: temporal-pg-backup-policy
      prefix: postgres/backups
    gcp:
      bucket: temporal-pg-backup-bucket
      cloudAccountName: my-gcs-cloud-account
      prefix: postgres/backups
    minio:
      endpoint: http://my-minio-workload:9000
      bucket: temporal-pg-backup-bucket
      accessKey: my-minio-username
      secretKey: my-minio-password
      prefix: postgres/backups

postgres: # dev/lightweight: single-instance PostgreSQL (disable postgresHA first)
  enabled: false
  config:
    username: temporal
    password: change-me-temporal-db-password # change before installing
    database: temporal
  volumeset:
    capacity: 10 # initial capacity in GiB (minimum is 10)
  backup:
    enabled: false # optional — see Backing Up
    image: ghcr.io/controlplane-com/backup-images/postgres-backup:18.1.0
    schedule: "0 2 * * *"
    resources:
      cpu: 100m
      memory: 128Mi
    provider: aws # options: aws, gcp, minio
    aws:
      bucket: temporal-pg-backup-bucket
      region: us-east-1
      cloudAccountName: my-s3-cloud-account
      policyName: temporal-pg-backup-policy
      prefix: postgres/backups
    gcp:
      bucket: temporal-pg-backup-bucket
      cloudAccountName: my-gcs-cloud-account
      prefix: postgres/backups
    minio:
      endpoint: http://my-minio-workload:9000
      bucket: temporal-pg-backup-bucket
      accessKey: my-minio-username
      secretKey: my-minio-password
      prefix: postgres/backups
```

### Temporal Server

* `image` — The upstream `auto-setup` image: at boot it creates the `temporal` and `temporal_visibility` databases, applies or upgrades the schema, registers the `default` namespace, then starts the server — all idempotently, so restarts and upgrades are safe. Image bumps apply new schema migrations automatically at boot.
* `resources` — CPU and memory for the server container.
* `historyShards` — The cluster's history shard count. **Permanent: fixed at the cluster's first boot and can never be changed** — the server refuses a different value later. Size it before installing; 512 suits most deployments.
* `namespaceRetention` — How long closed workflow histories stay queryable in the `default` namespace (e.g. `72h`, `96h`).

### Web UI

* `ui.enabled` — Set `false` to remove the UI workload.
* `ui.image` / `ui.resources` — The Temporal UI container image and its CPU/memory.

<Warning>
  The Temporal Web UI has **no built-in authentication** and is internal-only by design — this template has no knob to expose it publicly. To offer browser access from outside the internal scope, put your own authenticating proxy in front of it.
</Warning>

### Access

Both workloads are internal-only — there is no public-access option in this template. The gRPC frontend serves workers and clients running as workloads in your org. `internalAccess.type` sets the internal firewall scope for both the gRPC frontend (`:7233`) and the UI (`:8080`):

| Type            | Description                                                            |
| --------------- | ---------------------------------------------------------------------- |
| `none`          | No internal access.                                                    |
| `same-gvc`      | Allow access from all workloads in the same GVC (default).             |
| `same-org`      | Allow access from all workloads in the same organization.              |
| `workload-list` | Allow access only from workloads listed in `internalAccess.workloads`. |

### Database

Enable exactly one of `postgresHA` (production, default) or `postgres` (dev/lightweight) — see [Choosing a Database Mode](#choosing-a-database-mode). In both modes, **change the database password before installing** (`postgresHA.postgres.password` / `postgres.config.password`). Temporal is wired to the active database automatically — the HAProxy leader endpoint in HA mode, or the single instance directly in dev mode.

## Connecting

| What                               | Value                                                                                                      |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| gRPC frontend (workers/clients)    | `{release}-temporal.{gvc}.cpln.local:7233`                                                                 |
| Namespace                          | `default`                                                                                                  |
| Web UI (internal)                  | `http://{release}-temporal-ui.{gvc}.cpln.local:8080`                                                       |
| PostgreSQL (internal, HA mode)     | `{release}-postgres-ha-proxy.{gvc}.cpln.local:5432`, credentials in the `{release}-postgres-config` secret |
| PostgreSQL (internal, single mode) | `{release}-postgres.{gvc}.cpln.local:5432`, credentials in the `{release}-pg-config` secret                |

<Warning>
  Always use the full `.cpln.local` FQDN in worker and client connection config — short workload names do not resolve.
</Warning>

### Running Workers

Workers run as their own workloads (in the internal access scope) and connect to the gRPC frontend. A minimal Python worker:

```python theme={null}
import asyncio
from temporalio.client import Client
from temporalio.worker import Worker

async def main():
    client = await Client.connect(
        "my-release-temporal.my-gvc.cpln.local:7233",  # full FQDN required
        namespace="default",
    )
    worker = Worker(
        client,
        task_queue="my-task-queue",
        workflows=[MyWorkflow],
        activities=[my_activity],
    )
    await worker.run()

if __name__ == "__main__":  # required — see note below
    asyncio.run(main())
```

<Note>
  Python workers must guard their entrypoint with `if __name__ == "__main__":` — the Temporal Python SDK's workflow sandbox re-imports the worker module, and an unguarded module-level `main()` crashes the worker.
</Note>

## Backing Up

Database backups are optional and disabled by default. They cover the Temporal databases — all workflow histories, task queues, timers, and visibility data. Enable them with `postgresHA.backup.enabled` or `postgres.backup.enabled` (matching your database mode), and complete the storage setup for your provider **before** installing. The values below are shown under `backup.*` — set them within the enabled database block.

<Tabs>
  <Tab title="AWS S3">
    <Steps>
      <Step title="Create a bucket">
        Create an S3 bucket. Set `backup.aws.bucket` and `backup.aws.region` to match.
      </Step>

      <Step title="Set up a Cloud Account">
        If you do not have one, [create a Cloud Account](https://docs.controlplane.com/guides/create-cloud-account) for your AWS account. Set `backup.aws.cloudAccountName` to its name.
      </Step>

      <Step title="Create a bucket-scoped IAM policy">
        Create an AWS IAM policy with the JSON below (replace `YOUR_BUCKET`), then set `backup.aws.policyName` to the policy's name:

        ```json theme={null}
        {
          "Version": "2012-10-17",
          "Statement": [{
            "Effect": "Allow",
            "Action": [
              "s3:ListBucket",
              "s3:GetBucketLocation",
              "s3:GetObject",
              "s3:PutObject",
              "s3:DeleteObject",
              "s3:AbortMultipartUpload"
            ],
            "Resource": [
              "arn:aws:s3:::YOUR_BUCKET",
              "arn:aws:s3:::YOUR_BUCKET/*"
            ]
          }]
        }
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Google Cloud Storage">
    <Steps>
      <Step title="Create a bucket">
        Create a GCS bucket. Set `backup.gcp.bucket` to its name.
      </Step>

      <Step title="Set up a Cloud Account">
        If you do not have one, [create a Cloud Account](https://docs.controlplane.com/guides/create-cloud-account) for your GCP project. Set `backup.gcp.cloudAccountName` to its name — the backup identity is granted access to the bucket keylessly (no stored credentials).
      </Step>
    </Steps>
  </Tab>

  <Tab title="S3-compatible (MinIO, R2, Wasabi)">
    <Steps>
      <Step title="Create a bucket">
        Create your bucket on the server. Set `backup.minio.bucket` to its name.
      </Step>

      <Step title="Set the endpoint">
        Set `backup.minio.endpoint` to the S3 API address including port. For the `minio` marketplace template deployed in the same GVC, this is `http://WORKLOAD_NAME:9000`.
      </Step>

      <Step title="Set credentials">
        Set `backup.minio.accessKey` and `backup.minio.secretKey` to credentials with access to the bucket.
      </Step>
    </Steps>
  </Tab>
</Tabs>

In HA mode, `backup.mode` selects `logical` (scheduled `pg_dump` via a cron workload) or `wal-g` (continuous WAL archiving). The single-instance mode takes scheduled logical dumps.

## Important Notes

* **Change the database password** (`postgresHA.postgres.password` / `postgres.config.password`) before installing.
* **`historyShards` is permanent** — the shard count is fixed at the cluster's first boot and can never be changed; the server refuses a different value later. Size it before installing (512 suits most deployments).
* **Never expose the Web UI publicly** — it has no built-in authentication. To offer browser access from outside the internal scope, put your own authenticating proxy in front of it.
* **Temporal connects and runs schema setup as the database superuser** provisioned by the PostgreSQL subchart — it needs `CREATE DATABASE` and DDL rights at every version upgrade.
* **Upgrades restart the single server replica and apply schema migrations automatically at boot** — expect a brief frontend outage per Helm upgrade; in-flight workflows resume where they left off once the server is back.
* **Keep the server at one replica** — manually scaling the workload will not form a working cluster (required inter-service ports are not declared and the database connection limit would be exceeded).
* **Uninstall deletes the database volume sets** — all workflow histories and state. Enable backups if the data matters.

## External References

<CardGroup cols={2}>
  <Card title="Temporal Documentation" icon="book" href="https://docs.temporal.io/">
    Official Temporal documentation
  </Card>

  <Card title="Self-Hosted Guide" icon="server" href="https://docs.temporal.io/self-hosted-guide">
    Running and operating a self-hosted Temporal service
  </Card>

  <Card title="SDKs" icon="code" href="https://docs.temporal.io/develop">
    Writing workflows, activities, and workers in every supported language
  </Card>

  <Card title="Namespaces" icon="folder-tree" href="https://docs.temporal.io/namespaces">
    Namespaces and workflow-history retention
  </Card>

  <Card title="Web UI Reference" icon="globe" href="https://docs.temporal.io/web-ui">
    The Temporal Web UI reference
  </Card>

  <Card title="Temporal Template" icon="github" href="https://github.com/controlplane-com/templates/tree/main/temporal">
    View the source files, default values, and chart definition
  </Card>
</CardGroup>
