> ## Documentation Index
> Fetch the complete documentation index at: https://controlplanecorporation-majid-docs-content-expansion.mintlify.site/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
  credentials: # the chart writes these into the secret named below — nothing for you to create
    username: temporal
    password: change-me-temporal-db-password # change before installing
    database: temporal
  config:
    credentialsSecretName: my-temporal-db-credentials # secret names are org-wide — give each release its own
  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
      credentialsSecretName: my-temporal-minio-credentials # dictionary secret holding accessKey + secretKey
      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** (`postgres.credentials.password`). Temporal is wired to the active database automatically — the HAProxy leader endpoint in HA mode, or the single instance directly in dev mode.

If you run more than one release of this template in the same organization, give each its own `postgres.config.credentialsSecretName`. Secret names are organization-wide, so a second release left on the default name is **refused at install** and creates nothing — the first release is unaffected.

<Warning>
  **Leave `postgres.credentials.database` set to `temporal`.** The server reads its database name as the literal `temporal`, and auto-setup creates only the visibility store alongside it — so any other value wedges the install permanently on `Unable to setup SQL schema: no usable database connection found`. Template version `1.1.0` refuses to render rather than let that happen, and names the reason.
</Warning>

<Warning>
  **Template version `1.0.0` did not compact the etcd cluster inside the bundled highly available database**, so etcd's backend grows with time alone and goes read-only once it reaches its 2 GiB quota — after roughly 110 days — taking PostgreSQL failover with it. Only installs running the HA database are affected (`postgresHA.enabled`, the default here); see [etcd History Compaction](/template-catalog/templates/postgres-highly-available#etcd-history-compaction) for the mechanism and the symptoms. Upgrade to `1.0.1` or later to turn compaction on: that stops further growth but cannot shrink a backend that has already grown, and a cluster that has already raised a `NOSPACE` alarm needs operator recovery rather than an upgrade.
</Warning>

## 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 secret named by `postgres.config.credentialsSecretName` |

<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">
        The two backing stores take these differently. In HA mode (`postgresHA`), set `backup.minio.accessKey` and `backup.minio.secretKey` to credentials with access to the bucket. In single-instance mode (`postgres`), those two values were removed: create a [dictionary secret](/guides/create-secret/dictionary) holding the keys `accessKey` and `secretKey`, and set `backup.minio.credentialsSecretName` to its name — see [MinIO backup prerequisites](/template-catalog/templates/postgres#minio) for the exact command.
      </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** (`postgres.credentials.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>
