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

# CockroachDB

> Deploy CockroachDB on Control Plane using the Template Catalog. Covers configuration, volumes, scaling, and multi-region Raft consensus with automatic failover.

## Overview

CockroachDB is a distributed SQL database that provides automatic replication, horizontal scalability, and built-in fault tolerance across multiple regions. This template deploys a multi-region CockroachDB cluster on Control Plane as a stateful workload with replica-direct load balancing.

Each location runs a configurable number of replicas that discover and join one another using Control Plane's internal DNS. On first deployment, the cluster initializes itself, creates a database and user, registers all regions, and sets the survival goal to `SURVIVE REGION FAILURE`.

### What Gets Created

* **GVC** — A dedicated GVC across the specified locations.
* **Stateful CockroachDB Workload** — CockroachDB (`v25.4.0`) with per-location replica scaling and replica-direct load balancing.
* **Standard PgBouncer Workload** *(enabled by default)* — A connection pooler that multiplexes application connections across all CockroachDB nodes. When enabled, this becomes the primary connection endpoint.
* **Volume Set** — Persistent ext4 storage (general-purpose-ssd) with final snapshot creation and 7-day retention.
* **Identity & Policy** — An identity bound to the workload with `reveal` access to the startup and user secrets, and cloud storage access when backup is enabled.
* **Secrets** — A startup script for cluster join/initialization and an opaque secret for the database user credential.
* **Backup Cron Workload** *(optional)* — A scheduled job that triggers a CockroachDB `BACKUP` SQL command to stream data directly to AWS S3 or GCS.

### Architecture

CockroachDB uses the [Raft consensus protocol](https://www.cockroachlabs.com/docs/stable/architecture/replication-layer#raft) to replicate data across nodes. Each Control Plane location maps to a CockroachDB locality region, and replicas advertise their address via internal DNS (`replica-N.WORKLOAD.LOCATION.GVC.cpln.local`).

With 3 or more regions and the `SURVIVE REGION FAILURE` survival goal, the cluster tolerates the complete loss of one region without impacting availability.

## Installation

This template has no external prerequisites unless backup is enabled. To install, follow the instructions for 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>

## Configuration

The default `values.yaml` for this template:

```yaml theme={null}
gvc:
  name: cockroach-gvc
  locations:
    - name: aws-us-west-2
      replicas: 3
    - name: aws-us-east-2
      replicas: 3
    - name: aws-eu-central-1
      replicas: 3

image: cockroachdb/cockroach:v25.4.0

resources:
  cpu: 2
  memory: 4Gi

database:
  name: mydb
  user: myuser

volumeset:
  capacity: 10 # initial capacity in GiB (minimum is 10)
  autoscaling:
    enabled: false # Set to true to enable autoscaling
    maxCapacity: 100 # Maximum capacity in GiB when autoscaling is enabled
    minFreePercentage: 10 # Minimum free percentage to trigger scaling when autoscaling is enabled
    scalingFactor: 1.2 # Scaling factor to determine how much to scale up when autoscaling is triggered

internal_access:
  type: same-gvc # options: same-gvc, same-org, workload-list; used for CockroachDB when pgbouncer is disabled
  workloads:  # Note: can only be used if type is workload-list
    #- //gvc/GVC_NAME/workload/WORKLOAD_NAME

pgbouncer:
  enabled: true
  image: edoburu/pgbouncer:v1.25.1-p0
  poolMode: transaction  # options: session, transaction, statement
  defaultPoolSize: 25    # number of real CockroachDB connections PgBouncer maintains per pod
  maxClientConn: 250     # maximum number of client connections PgBouncer accepts per pod
  maxDbConnections: 100  # hard cap on total CockroachDB connections regardless of how many PgBouncer pods are running
  minReplicas: 2
  maxReplicas: 4
  serverCheckDelay: 30      # seconds between idle server connection health checks
  serverConnectTimeout: 2   # seconds before giving up on a new server connection
  serverLoginRetry: 0       # seconds before retrying a failed server login; 0 = no caching of failures
  clientLoginTimeout: 10    # seconds before rejecting a client waiting for login
  queryWaitTimeout: 10      # seconds before rejecting a logged-in client waiting for a server connection
  internal_access:
    type: same-gvc # options: same-gvc, same-org, workload-list; controls who can connect to PgBouncer
    workloads:  # Note: can only be used if type is workload-list
      #- //gvc/GVC_NAME/workload/WORKLOAD_NAME
  resources:
    cpu: 200m
    minCpu: 100m
    memory: 1Gi
    minMemory: 128Mi

backup:
  enabled: false
  image: controlplanecorporation/cockroach-backup:1.0
  schedule: "0 2 * * *"
  activeDeadlineSeconds: 14400   # hard kill after 4 hours if backup hangs
  location: aws-us-east-2        # run the backup job in the same region as your storage bucket
  resources:
    cpu: 500m
    memory: 512Mi
  provider: aws  # options: aws, gcp
  aws:
    bucket: my-backup-bucket
    region: us-east-1
    cloudAccountName: my-backup-cloudaccount
    policyName: my-backup-policy
    prefix: cockroach/backups
  gcp:
    bucket: my-backup-bucket
    cloudAccountName: my-backup-cloudaccount
    prefix: cockroach/backups
```

### Locations and Replicas

Configure the `gvc.locations` section to control which regions the cluster spans and how many replicas run in each.

<Note>
  While CockroachDB can run on 1 location, a minimum of 3 locations with 3 replicas per location is recommended. This is the minimum required for CockroachDB to survive a full region failure.
</Note>

Setting a location's `replicas` to `0` suspends the workload in that location without removing it from the configuration.

### Database Initialization

The `database` section specifies a database and user to create automatically when the cluster first initializes:

```yaml theme={null}
database:
  name: mydb
  user: myuser
```

The created user is granted full access to the specified database.

<Note>
  These values are only applied on the first initialization. If the cluster has already been initialized, they are skipped on restart or upgrade. To change credentials or the database name on an existing cluster, use CockroachDB's native commands (e.g. `ALTER USER`, `RENAME DATABASE`).
</Note>

### Resources and Storage

* `resources.cpu` and `resources.memory` set the CPU and memory allocated to each CockroachDB replica.
* `volumeset.capacity` sets the initial persistent volume size in GiB (minimum 10).
* `volumeset.autoscaling.enabled` — Enable automatic volume expansion as data grows.
* `volumeset.autoscaling.maxCapacity` — Maximum volume size in GiB.
* `volumeset.autoscaling.minFreePercentage` — Triggers a scale-up when free space falls below this percentage.
* `volumeset.autoscaling.scalingFactor` — Multiplier applied to the current capacity on each scale-up.

### Internal Access

The `internal_access` section controls which workloads can reach CockroachDB directly. When PgBouncer is enabled, `internal_access` only applies to direct CockroachDB connections — use `pgbouncer.internal_access` to control who can connect through PgBouncer.

| Type            | Description                                                     |
| --------------- | --------------------------------------------------------------- |
| `same-gvc`      | Allow access from all workloads in the same GVC                 |
| `same-org`      | Allow access from all workloads in the same organization        |
| `workload-list` | Allow access only from specific workloads listed in `workloads` |

When using `workload-list`, specify each workload using its full link format:

```yaml theme={null}
internal_access:
  type: workload-list
  workloads:
    - //gvc/GVC_NAME/workload/WORKLOAD_NAME
```

### PgBouncer Connection Pooling

PgBouncer is enabled by default. It multiplexes application connections into a smaller pool of real database connections, reducing overhead and protecting CockroachDB from connection exhaustion under high concurrency. It connects to all CockroachDB nodes across all locations, so failover and load distribution are handled transparently.

When enabled, PgBouncer becomes the primary connection endpoint — connect to it instead of CockroachDB directly:

```
RELEASE_NAME-pgbouncer.GVC_NAME.cpln.local:5432
```

**Pool modes:**

| Mode          | Behavior                                                                                                                                                               |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `transaction` | Connection held only for the duration of a transaction. Best for most web and API workloads. Not compatible with `SET` variables, temporary tables, or advisory locks. |
| `session`     | Connection held for the entire client session. Compatible with all features but provides less connection reuse.                                                        |
| `statement`   | Connection returned after every statement. Transactions are not supported. Rarely used.                                                                                |

* `pgbouncer.defaultPoolSize` — Real CockroachDB connections PgBouncer maintains per pod.
* `pgbouncer.maxClientConn` — Maximum client connections PgBouncer accepts per pod.
* `pgbouncer.maxDbConnections` — Hard cap on total CockroachDB connections shared across all PgBouncer pods. Set this to a value your cluster can safely handle regardless of how many pods are running.
* `pgbouncer.minReplicas` / `pgbouncer.maxReplicas` — PgBouncer autoscales on RPS between these bounds.
* `pgbouncer.internal_access` — Controls which workloads can connect to PgBouncer (same options as `internal_access`).

### Connecting to CockroachDB

When PgBouncer is enabled (default), connect through it on port 5432:

```bash theme={null}
psql "host=RELEASE_NAME-pgbouncer.GVC_NAME.cpln.local port=5432 dbname=mydb user=myuser sslmode=disable"
```

When PgBouncer is disabled, connect directly to CockroachDB on port 26257:

```bash theme={null}
cockroach sql --insecure --host=RELEASE_NAME-cockroach.GVC_NAME.cpln.local:26257
```

<Note>
  This template deploys CockroachDB in insecure mode (no TLS). It is intended for internal workloads that connect through Control Plane's internal network, where mTLS is handled by Control Plane.
</Note>

The DB Console (HTTP UI) runs on port 8080 for monitoring cluster health, query performance, and node status. It is not exposed externally — access it via port forward and open `http://localhost:8080` in your browser.

### Application Retry Logic

Your application must implement retry logic on database connections. PgBouncer routes around failed CockroachDB nodes, but transient errors are still surfaced to the application during failover events — such as a location outage or rolling restarts — while PgBouncer cycles through backends and Raft leader elections complete. Without retries, these transient errors will propagate directly to the client.

<Note>
  This template creates a GVC with a default name defined in the values file. If you plan to deploy multiple instances, you **must assign a unique GVC name** for each deployment.
</Note>

## Backup

Backup is disabled by default. When enabled, a cron workload triggers a CockroachDB `BACKUP` SQL command on the configured schedule. CockroachDB nodes stream backup data directly to cloud storage using their own workload identity — the backup job only issues the SQL command and does not transfer data itself.

* `backup.enabled` — Enable scheduled backups.
* `backup.schedule` — Cron expression for backup frequency (default: daily at 2am UTC).
* `backup.provider` — `aws` or `gcp`.
* `backup.location` — The Control Plane location where the backup cron job runs. **Set this to the region closest to your storage bucket** to minimize cross-region transfer latency.
* `backup.activeDeadlineSeconds` — Hard timeout for the backup job in seconds (default: `14400` / 4 hours). The job is killed if it exceeds this limit.
* `backup.resources.cpu` / `backup.resources.memory` — Resources for the backup cron container.

### AWS S3

Before enabling backup with `provider: aws`, complete the following in your AWS account:

1. Create an S3 bucket. Set `backup.aws.bucket` to its name and `backup.aws.region` to its region.
2. If you do not have a Cloud Account set up, refer to the docs to [Create a Cloud Account](/guides/create-cloud-account). Set `backup.aws.cloudAccountName` to its name.
3. Create an IAM policy with the following JSON, replacing `YOUR_BUCKET_NAME`:

```json theme={null}
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject",
                "s3:ListBucket",
                "s3:GetObjectVersion",
                "s3:DeleteObjectVersion"
            ],
            "Resource": [
                "arn:aws:s3:::YOUR_BUCKET_NAME",
                "arn:aws:s3:::YOUR_BUCKET_NAME/*"
            ]
        }
    ]
}
```

4. Set `backup.aws.policyName` to the name of the policy created in step 3.
5. Set `backup.aws.prefix` to the folder path where backups will be stored.

### GCS

Before enabling backup with `provider: gcp`, complete the following in your GCP account:

1. Create a GCS bucket. Set `backup.gcp.bucket` to its name.
2. If you do not have a Cloud Account set up, refer to the docs to [Create a Cloud Account](/guides/create-cloud-account). Set `backup.gcp.cloudAccountName` to its name.
3. Add the **Storage Admin** role to the GCP service account associated with the Cloud Account.
4. Set `backup.gcp.prefix` to the folder path where backups will be stored.

## Restoring a Backup

Backups are stored at `BUCKET/PREFIX/`. Run `cockroach sql` from a machine with network access to the cluster.

**AWS S3**

```sh theme={null}
cockroach sql --insecure \
  --host="RELEASE_NAME-cockroach.GVC_NAME.cpln.local:26257" \
  --execute="RESTORE FROM LATEST IN 's3://BUCKET_NAME/PREFIX?AUTH=implicit&AWS_REGION=BUCKET_REGION';"
```

**GCS**

```sh theme={null}
cockroach sql --insecure \
  --host="RELEASE_NAME-cockroach.GVC_NAME.cpln.local:26257" \
  --execute="RESTORE FROM LATEST IN 'gs://BUCKET_NAME/PREFIX?AUTH=implicit';"
```

## External References

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

  <Card title="Multi-Region Overview" icon="globe" href="https://www.cockroachlabs.com/docs/stable/multiregion-overview">
    Learn about multi-region deployments
  </Card>

  <Card title="Survive Region Failure" icon="shield" href="https://www.cockroachlabs.com/docs/stable/alter-database#survive-region-failure">
    Configure region failure survival goals
  </Card>

  <Card title="Backup Image Source" icon="github" href="https://github.com/controlplane-com/backup-images/tree/main/cockroach-backup">
    Source code for the CockroachDB backup container image
  </Card>

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