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

# Unleash

> Deploy Unleash on Control Plane using the Template Catalog. Open-source feature-flag server with an admin UI and SDK APIs, backed by a highly available PostgreSQL cluster. Covers replicas, first-boot API token seeding, database modes, and backups.

## Overview

Unleash is an open-source feature-flag server — toggle features on and off, roll them out gradually, and run A/B tests without redeploying your applications. This template deploys the free open-source edition backed by a highly available PostgreSQL cluster by default. The admin UI and the Admin, Client, and Frontend APIs are served on one public HTTPS endpoint, and the server is stateless — every flag, user, and token lives in PostgreSQL — so it scales to multiple replicas with a single value.

### Architecture

* **Unleash** — A standard workload (default 1 replica, `replicas` knob for more) serving the admin UI and all APIs on port `4242`. Stateless by design: all state lives in the PostgreSQL database, so Unleash itself has no volume set. The public URL (`UNLEASH_URL`) is derived from the canonical endpoint at start.
* **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 Unleash 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 Unleash Workload** — One or more stateless replicas serving the admin UI and the Admin, Client, and Frontend APIs on port `4242`.
* **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). Unleash itself has none.
* **Secrets** — Admin bootstrap credentials, the start script that derives the public URL at runtime, and the database credentials from the subchart.
* **Identity & Policy** — A least-privilege policy granting the Unleash identity `reveal` on exactly the secrets it uses, including your pre-created API-token secret when one is configured.
* **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 — install, log in with `admin.username` / `admin.password`, and create SDK API tokens in the admin UI.

Optionally, the template can seed a backend and a frontend SDK API token on first boot from a [dictionary secret](/guides/create-secret/dictionary) that you create **before** installing. The token strings are never passed through values.

<Steps>
  <Step title="Generate token strings">
    An Unleash token has the format `<project>:<environment>.<secret>`. The open-source edition ships the `default` project and the `development` and `production` environments. For example:

    ```bash theme={null}
    echo "default:production.$(openssl rand -hex 24)"
    ```

    Generate one token string for backend SDKs and one for frontend SDKs.
  </Step>

  <Step title="Create a dictionary secret">
    Create a [dictionary secret](/guides/create-secret/dictionary) in your org with exactly two keys, `backend` and `frontend`, each holding a full token string.
  </Step>

  <Step title="Reference it in values">
    Set `apiTokens.secretName` to the secret's name. Leave it empty to skip seeding and create tokens in the admin UI instead.
  </Step>
</Steps>

For optional database backups, you also 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 takes roughly 5–7 minutes to fully converge; transient `Failed to migrate db` log errors while the database cluster starts are expected and self-heal, at any replica count. Single mode is ready in about a minute.

## Configuration

The default `values.yaml` for this template:

```yaml theme={null}
image: unleashorg/unleash-server:8.0.3

resources:
  cpu: 1000m
  memory: 1Gi
  minCpu: 250m
  minMemory: 512Mi

replicas: 1 # stateless server — set 2+ for high availability (all state lives in PostgreSQL)

admin: # initial admin login, seeded on first boot only
  username: admin
  password: change-me-unleash-admin # change before installing

apiTokens:
  secretName: "" # your pre-created dictionary secret (see Prerequisites); empty = create tokens in the UI

publicAccess:
  enabled: true # admin UI + SDK APIs on the canonical *.cpln.app HTTPS endpoint

internalAccess: # internal firewall scope (in-GVC SDK callers)
  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: unleash
    password: change-me-unleash-db-password # change before installing
    database: unleash
  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: unleash-pg-backup-bucket
      region: us-east-1
      cloudAccountName: my-s3-cloud-account
      policyName: unleash-pg-backup-policy
      prefix: postgres/backups
    gcp:
      bucket: unleash-pg-backup-bucket
      cloudAccountName: my-gcs-cloud-account
      prefix: postgres/backups
    minio:
      endpoint: http://my-minio-workload:9000
      bucket: unleash-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: unleash
    password: change-me-unleash-db-password # change before installing
    database: unleash
  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: unleash-pg-backup-bucket
      region: us-east-1
      cloudAccountName: my-s3-cloud-account
      policyName: unleash-pg-backup-policy
      prefix: postgres/backups
    gcp:
      bucket: unleash-pg-backup-bucket
      cloudAccountName: my-gcs-cloud-account
      prefix: postgres/backups
    minio:
      endpoint: http://my-minio-workload:9000
      bucket: unleash-pg-backup-bucket
      accessKey: my-minio-username
      secretKey: my-minio-password
      prefix: postgres/backups
```

### Unleash Instance

* `image` — The Unleash open-source server image.
* `resources` — CPU and memory for the Unleash container.
* `replicas` — Number of Unleash replicas behind the platform load balancer. The server is stateless, so scaling is a single value change; `2+` is recommended for production. At 2 replicas, rolling redeploys and a killed replica were both verified to serve every request with zero failures.
* `admin.*` — The initial admin login, seeded into the database on first boot only. **Change `admin.password` before installing** — the upstream default password is rejected once your own is set. Changing these values later does not modify the existing account; change the password in the admin UI instead.
* `apiTokens.secretName` — Name of your pre-created dictionary secret with keys `backend` and `frontend` (see [Prerequisites](#prerequisites)). When set, both tokens are seeded on first boot; when empty (default), create tokens in the admin UI after install. Like the admin account, tokens are seeded on first boot only.

### Access

* `publicAccess.enabled` — Serve the admin UI and SDK APIs on the canonical `*.cpln.app` HTTPS endpoint (default). Every surface is authenticated — the UI and Admin API by login, the Client and Frontend APIs by tokens. Set to `false` for an internal-only instance (external requests are blocked at the edge; in-GVC callers still reach it per `internalAccess`). The public URL Unleash embeds in password-reset and invite links (`UNLEASH_URL`) is derived at startup — from the canonical endpoint when public, or the internal `cpln.local` address when not — and re-derived on every restart.
* `internalAccess.type` — Internal firewall scope of the Unleash workload:

| 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`). Unleash 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                                                                                                      |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| Admin UI / Admin API (public)      | `https://<canonical>.cpln.app` — `status.canonicalEndpoint` of `{release}-unleash`                         |
| Client API (backend SDKs)          | `https://<canonical>.cpln.app/api/client` — `Authorization: <backend token>`                               |
| Frontend API (browser/mobile SDKs) | `https://<canonical>.cpln.app/api/frontend` — `Authorization: <frontend token>`                            |
| Internal (same GVC)                | `http://{release}-unleash.{gvc}.cpln.local:4242`                                                           |
| Login                              | `admin.username` / `admin.password`                                                                        |
| 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                |

### API Tokens

SDKs authenticate with an API token in the `Authorization` header. The two token types are not interchangeable:

* **Backend tokens** authenticate server-side SDKs against `/api/client`. Treat them like passwords — they must stay secret.
* **Frontend tokens** authenticate browser and mobile SDKs against `/api/frontend`. They are designed to be publishable and safe to embed in client code.

A `401` or `403` from an SDK API usually means the wrong token type for the endpoint, or the wrong environment in the token string. Tokens come either from your prerequisite secret (seeded on first boot) or from the admin UI (**Admin → API access**) at any time.

## Backing Up

Database backups are optional and disabled by default. They cover the PostgreSQL database — every flag, strategy, user, and token in your Unleash instance. 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:GetObjectVersion",
              "s3:PutObject",
              "s3:DeleteObject",
              "s3:DeleteObjectVersion",
              "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 — access is keyless (no stored credentials).
      </Step>

      <Step title="Grant the Storage Admin role">
        Grant the **Storage Admin** role to the GCP service account created for the Cloud Account (`roles/storage.objectAdmin` scoped to the bucket also works).
      </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 `admin.password` and the database password** (`postgresHA.postgres.password` / `postgres.config.password`) before installing.
* **Admin credentials and API tokens are seeded on first boot only** — they live in the database afterwards; change the password or manage tokens in the admin UI, not by upgrading values.
* **Backend tokens must stay secret** (server-side SDKs, `/api/client`); frontend tokens are safe to embed in browsers (`/api/frontend`). A `401` usually means the wrong token type or environment.
* **The free edition ships exactly two environments** (`development`, `production`) — SSO, role-based access control, multiple projects, change requests, and audit logs require an Unleash Enterprise license and are not available in this template.
* **HA-mode first boot takes \~5–7 minutes** — transient `Failed to migrate db` log errors while the database cluster starts are expected and self-heal, at any replica count.
* **Uninstall deletes the database volume sets** — all flags, users, and tokens. Enable backups if the data matters.

## External References

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

  <Card title="Configuring Unleash" icon="gear" href="https://docs.getunleash.io/deploy/configuring-unleash">
    Environment variable configuration reference
  </Card>

  <Card title="API Tokens and Client Keys" icon="key" href="https://docs.getunleash.io/concepts/api-tokens-and-client-keys">
    Token types, formats, and how SDKs authenticate
  </Card>

  <Card title="SDK Overview" icon="code" href="https://docs.getunleash.io/sdks">
    Official backend and frontend SDKs
  </Card>

  <Card title="Scaling Unleash" icon="server" href="https://docs.getunleash.io/guides/scaling-unleash">
    Upstream guidance on horizontal scaling
  </Card>

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