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

# Metabase

> Deploy Metabase on Control Plane using the Template Catalog. Open-source BI with dashboards, a SQL editor, and scheduled reports, backed by a highly available PostgreSQL app database. Covers the encryption-key prerequisite, database modes, first-boot admin setup, and backups.

## Overview

Metabase is an open-source business intelligence platform — dashboards, a SQL editor, and scheduled report subscriptions. This template deploys the free open-source edition backed by a highly available PostgreSQL cluster by default. The bundled PostgreSQL is Metabase's own **app database** (users, dashboards, saved connections); the databases you analyze are **data sources** you connect in the app after install — they are never installed or touched by this template. The admin account is created automatically on first boot, and the workload only starts receiving traffic once setup is complete, so there is never a publicly reachable setup page.

### Architecture

* **Metabase** — A single-replica standard workload serving the UI and API on port `3000`. Stateless by design: all application state (questions, dashboards, users, saved connections) lives in the PostgreSQL app database, so Metabase itself has no volume set.
* **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 Metabase 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 Metabase Workload** — A single stateless replica serving the UI and API on port `3000`.
* **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). Metabase itself has none.
* **Secrets** — Admin bootstrap credentials, the start script that creates the admin account on first boot, and the database credentials from the subchart.
* **Identity & Policy** — A least-privilege policy granting the Metabase identity `reveal` on exactly the secrets it uses, including your pre-created encryption-key secret.
* **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

Metabase encrypts the connection details of every data source you save with a key it reads from an [opaque secret](/guides/create-secret/opaque) that you create **before** installing. The key is never passed through values.

<Steps>
  <Step title="Generate an encryption key">
    Generate a random string of at least 16 characters, for example:

    ```bash theme={null}
    openssl rand -hex 24
    ```
  </Step>

  <Step title="Create an opaque secret">
    Create an [opaque secret](/guides/create-secret/opaque) in your org with encoding `plain` whose payload is the generated key. Set its name in `encryptionKey.secretName`.
  </Step>

  <Step title="Back up the key">
    Store a copy of the key somewhere safe, outside Control Plane.
  </Step>
</Steps>

<Warning>
  Losing or changing the encryption key means re-entering every saved database connection — Metabase can no longer decrypt them. Rotation is only possible offline, using Metabase's `rotate-encryption-key` command. Back the key up before installing.
</Warning>

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

Once your encryption-key secret exists, 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 10–15 minutes to fully converge; single mode is ready in about 2 minutes.

## Configuration

The default `values.yaml` for this template:

```yaml theme={null}
image: metabase/metabase:v0.63.1.3

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

encryptionKey:
  secretName: my-metabase-encryption-key # name of your pre-created opaque secret (see Prerequisites)

admin: # admin account, created automatically on first boot
  email: admin@example.com # admin login email
  firstName: Metabase
  lastName: Admin
  password: change-me-metabase-1 # change before installing; letters + digits, 8+ chars

siteName: Metabase # instance name shown in the UI and emails

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

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

### Metabase Instance

* `image` — The Metabase open-source container image.
* `resources` — CPU and memory for the Metabase container. The template caps the JVM at 75% of the container memory limit (`JAVA_OPTS: -XX:MaxRAMPercentage=75.0`), so raising `resources.memory` also raises the Java heap. The 2 GiB default is sized for the JVM — lowering it is not recommended.
* `encryptionKey.secretName` — Name of your pre-created opaque secret holding the key that encrypts saved data-source credentials. See [Prerequisites](#prerequisites).
* `admin.*` — The admin account, created automatically on first boot against the local setup API. There is no unauthenticated setup page at any point: the workload only becomes ready — and only starts receiving traffic — once setup is complete, and if setup fails it never becomes ready at all (fail-closed). **Change `admin.password` before installing** — it must pass Metabase's complexity check (letters + digits, 8+ characters), and none of the `admin.*` values may contain double quotes or backslashes (enforced at render). The account is created exactly once, on first boot — changing these values later does not modify the existing account.
* `siteName` — The instance name shown in the UI and in emails Metabase sends.

### Access

* `publicAccess.enabled` — Serve the UI and API on the canonical `*.cpln.app` HTTPS endpoint (default). Everything behind the endpoint is gated by Metabase's own login. Set to `false` for an internal-only instance (external requests are blocked at the edge; in-GVC callers still reach it per `internalAccess`).
* `internalAccess.type` — Internal firewall scope of the Metabase 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`. |

### App 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`). Metabase 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                                                                                                      |
| ------------------------------------ | ---------------------------------------------------------------------------------------------------------- |
| UI / API (public)                    | `https://<canonical>.cpln.app` — `status.canonicalEndpoint` of `{release}-metabase`                        |
| Internal (same GVC)                  | `http://{release}-metabase.{gvc}.cpln.local:3000`                                                          |
| Login                                | `admin.email` / `admin.password`                                                                           |
| App database (internal, HA mode)     | `{release}-postgres-ha-proxy.{gvc}.cpln.local:5432`, credentials in the `{release}-postgres-config` secret |
| App database (internal, single mode) | `{release}-postgres.{gvc}.cpln.local:5432`, credentials in the `{release}-pg-config` secret                |

### Adding Data Sources

The databases you analyze are added inside Metabase after install (**Admin → Databases**) — the template never installs or touches them. To analyze a database running on Control Plane, use its internal endpoint as the host, e.g. `{workload}.{gvc}.cpln.local:5432`. Any database Metabase can reach — inside or outside Control Plane — works as a data source. Saved connection credentials are encrypted at rest with your encryption key.

## Backing Up

Database backups are optional and disabled by default. They cover the app database — the questions, dashboards, users, and saved connections that make up your Metabase 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: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

* **Back up the encryption-key secret** — losing or changing it means re-entering every saved database connection; rotation is only possible offline via Metabase's `rotate-encryption-key` command.
* **Change `admin.password` and the database password** (`postgresHA.postgres.password` / `postgres.config.password`) before installing. An admin password that fails Metabase's complexity check (letters + digits, 8+ characters) keeps the workload unready by design.
* **Metabase is single-replica in this template** — the default HA PostgreSQL backend removes the database as a failure point.
* **Upgrades restart the single replica** — expect a few minutes of UI downtime per Helm upgrade; the HA app database keeps running and no data is lost.
* **Uninstall deletes the app-database volume sets** — all questions, dashboards, and users. Enable backups if the data matters.
* **This template ships the open-source image only** — Pro/Enterprise features (SSO, sandboxing, config-file init) are not available.

## External References

<CardGroup cols={2}>
  <Card title="Metabase Documentation" icon="book" href="https://www.metabase.com/docs/latest/">
    Official Metabase documentation
  </Card>

  <Card title="Environment Variables" icon="gear" href="https://www.metabase.com/docs/latest/configuring-metabase/environment-variables">
    Metabase environment variables reference
  </Card>

  <Card title="Encrypting Database Details" icon="lock" href="https://www.metabase.com/docs/latest/databases/encrypting-details-at-rest">
    How the encryption key protects saved connection credentials
  </Card>

  <Card title="Metabase in Production" icon="server" href="https://www.metabase.com/learn/metabase-basics/administration/administration-and-operation/metabase-in-production">
    Upstream guidance on running Metabase in production
  </Card>

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