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

# Terraform Provider

> Manage Rivestack HA PostgreSQL clusters as infrastructure-as-code

The official [Rivestack Terraform provider](https://registry.terraform.io/providers/Rivestack/rivestack/latest) lets you manage clusters, databases, users, extensions, grants, and backups as code.

## Installation

Add the provider to your Terraform configuration:

```hcl theme={null}
terraform {
  required_providers {
    rivestack = {
      source  = "rivestack/rivestack"
      version = "~> 0.1"
    }
  }
}

provider "rivestack" {}
```

Requires **Terraform >= 1.0**.

## Authentication

Get your API key from the [Rivestack Dashboard](https://app.rivestack.io). API keys use the `rsk_` prefix.

<Tabs>
  <Tab title="Environment variable (recommended)">
    ```bash theme={null}
    export RIVESTACK_API_KEY="rsk_your_api_key"
    ```
  </Tab>

  <Tab title="Provider configuration">
    ```hcl theme={null}
    provider "rivestack" {
      api_key = "rsk_your_api_key"
    }
    ```
  </Tab>
</Tabs>

## Node capacity

HA clusters run on **prepaid node capacity**, not per-cluster billing. You buy a pool of nodes once, then Terraform (or the API) provisions clusters that draw from it — there's no checkout in your `terraform apply` loop.

<Steps>
  <Step title="Buy capacity in the dashboard">
    In the [Rivestack Dashboard](https://app.rivestack.io), go to **Billing → Subscribe to Nodes**, choose a server type (`starter`, `growth`, or `scale`) and a quantity, then complete checkout. This is the only step that involves payment.
  </Step>

  <Step title="Provision against the pool">
    `terraform apply` draws nodes from your pool automatically, matching on `server_type`. A `growth` cluster with `node_count = 2` consumes two `growth` nodes from your `growth` pool. There is no extra charge per cluster.
  </Step>
</Steps>

<Warning>
  If your pool has no free nodes of the requested `server_type`, the API returns **402 Payment Required** (`no available nodes; subscribe to nodes from the billing page first`) and `terraform apply` fails. Buy more capacity of that server type, then re-run.
</Warning>

### Provision with the REST API

If you don't use Terraform, call the same endpoint directly. Create an API key, buy capacity, then:

```bash theme={null}
# Provision a cluster from your prepaid pool (draws a matching node automatically)
curl -X POST https://api.rivestack.io/api/ha/provision \
  -H "Authorization: Bearer rsk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "production-cluster",
    "region": "eu-central",
    "server_type": "growth",
    "node_count": 2,
    "postgresql_version": 18
  }'
# region accepts "eu-central", "us-east", or "ap" (Singapore)
# → { "id": 42, "tenant_id": "rs-…", "status": "provisioning", … }

# Poll until status is "active"
curl https://api.rivestack.io/api/ha/42 \
  -H "Authorization: Bearer rsk_your_api_key"
```

<Info>
  Omit `server_type` to default to `starter`. The cluster is matched to a pool of the same server type and capacity is found automatically — no pool ID needed.
</Info>

## Quick start

This example creates a 2-node HA cluster with a database and user:

```hcl theme={null}
terraform {
  required_providers {
    rivestack = {
      source  = "rivestack/rivestack"
      version = "~> 0.1"
    }
  }
}

provider "rivestack" {}

# Create an HA PostgreSQL cluster
resource "rivestack_cluster" "production" {
  name               = "production-cluster"
  region             = "eu-central"
  server_type        = "growth"
  node_count         = 2
  postgresql_version = 18
}

# Create a database
resource "rivestack_cluster_database" "analytics" {
  cluster_id = rivestack_cluster.production.id
  name       = "analytics"
  owner      = rivestack_cluster.production.db_user
}

# Create a user
resource "rivestack_cluster_user" "app_user" {
  cluster_id = rivestack_cluster.production.id
  username   = "app_user"
}

# Outputs
output "cluster_host" {
  value = rivestack_cluster.production.host
}

output "connection_string" {
  value     = rivestack_cluster.production.connection_string
  sensitive = true
}

output "app_user_password" {
  value     = rivestack_cluster_user.app_user.password
  sensitive = true
}
```

```bash theme={null}
terraform init
terraform plan
terraform apply
```

## Resources

### rivestack\_cluster

Manages an HA PostgreSQL cluster.

```hcl theme={null}
resource "rivestack_cluster" "example" {
  name               = "my-cluster"
  region             = "eu-central"
  server_type        = "starter"
  node_count         = 2
  postgresql_version = 18
}
```

| Attribute            | Type   | Required | Description                                          |
| -------------------- | ------ | -------- | ---------------------------------------------------- |
| `name`               | String | Yes      | Display name for the cluster                         |
| `region`             | String | Yes      | Region: `eu-central`, `us-east`, or `ap` (Singapore) |
| `server_type`        | String | No       | Server size: `starter`, `growth`, or `scale`         |
| `node_count`         | Number | No       | Number of nodes (1-3)                                |
| `postgresql_version` | Number | No       | PostgreSQL major version (16, 17, or 18)             |
| `db_name`            | String | No       | Name of the default database                         |
| `db_type`            | String | No       | Cluster type: `ha` or `core_solo`                    |
| `extensions`         | List   | No       | Extensions to install at creation time               |

**Read-only attributes:** `id`, `host`, `connection_string`, `db_user`, `db_password`, `status`, `tenant_id`, `created_at`, `updated_at`

### rivestack\_cluster\_database

Creates a database on a cluster.

```hcl theme={null}
resource "rivestack_cluster_database" "example" {
  cluster_id = rivestack_cluster.example.id
  name       = "analytics"
  owner      = rivestack_cluster.example.db_user
}
```

| Attribute    | Type   | Required | Description                                                  |
| ------------ | ------ | -------- | ------------------------------------------------------------ |
| `cluster_id` | String | Yes      | ID of the cluster                                            |
| `name`       | String | Yes      | Database name                                                |
| `owner`      | String | No       | Database owner username (defaults to cluster's default user) |

### rivestack\_cluster\_user

Creates a database user with an auto-generated password.

```hcl theme={null}
resource "rivestack_cluster_user" "example" {
  cluster_id = rivestack_cluster.example.id
  username   = "app_user"
}
```

| Attribute    | Type   | Required | Description                                            |
| ------------ | ------ | -------- | ------------------------------------------------------ |
| `cluster_id` | String | Yes      | ID of the cluster                                      |
| `username`   | String | Yes      | Username (letters, numbers, underscores; max 63 chars) |

**Read-only attributes:** `id`, `password` (sensitive)

### rivestack\_cluster\_grant

Grants a user access to a database.

```hcl theme={null}
resource "rivestack_cluster_grant" "example" {
  cluster_id = rivestack_cluster.example.id
  username   = rivestack_cluster_user.example.username
  database   = rivestack_cluster_database.example.name
  access     = "read"
}
```

| Attribute    | Type   | Required | Description                                                               |
| ------------ | ------ | -------- | ------------------------------------------------------------------------- |
| `cluster_id` | String | Yes      | ID of the cluster                                                         |
| `username`   | String | Yes      | Username to grant access to                                               |
| `database`   | String | Yes      | Database to grant access on                                               |
| `access`     | String | No       | Access level: `read` (SELECT) or `write` (SELECT, INSERT, UPDATE, DELETE) |

<Info>Grant revocation is not currently supported by the API. Destroying this resource removes it from Terraform state only.</Info>

### rivestack\_cluster\_extension

Installs a PostgreSQL extension on a database.

```hcl theme={null}
resource "rivestack_cluster_extension" "vector" {
  cluster_id = rivestack_cluster.example.id
  extension  = "vector"
  database   = rivestack_cluster_database.example.name
}
```

| Attribute    | Type   | Required | Description                                              |
| ------------ | ------ | -------- | -------------------------------------------------------- |
| `cluster_id` | String | Yes      | ID of the cluster                                        |
| `extension`  | String | Yes      | Extension name (e.g., `vector`, `pg_trgm`, `pgcrypto`)   |
| `database`   | String | No       | Target database (defaults to cluster's primary database) |

<Info>Extensions cannot be removed from running clusters. Destroying this resource removes it from Terraform state only.</Info>

### rivestack\_cluster\_backup\_config

Configures automated backups for a cluster.

```hcl theme={null}
resource "rivestack_cluster_backup_config" "example" {
  cluster_id     = rivestack_cluster.example.id
  enabled        = true
  schedule       = "0 3 * * *"
  retention_full = 14
}
```

| Attribute        | Type    | Required | Description                                           |
| ---------------- | ------- | -------- | ----------------------------------------------------- |
| `cluster_id`     | String  | Yes      | ID of the cluster                                     |
| `enabled`        | Boolean | Yes      | Whether automated backups are enabled                 |
| `schedule`       | String  | No       | Cron schedule (e.g., `"0 3 * * *"` for daily at 3 AM) |
| `retention_full` | Number  | No       | Number of days to retain full backups                 |

## Data sources

### rivestack\_cluster

Read information about an existing cluster.

```hcl theme={null}
data "rivestack_cluster" "existing" {
  id = "42"
}

output "cluster_host" {
  value = data.rivestack_cluster.existing.host
}
```

**Read-only attributes:** `name`, `region`, `server_type`, `node_count`, `postgresql_version`, `host`, `connection_string`, `db_name`, `db_user`, `db_password`, `db_type`, `status`, `health_status`, `tenant_id`, `created_at`, `updated_at`

### rivestack\_server\_types

List available server configurations.

```hcl theme={null}
data "rivestack_server_types" "available" {}
```

### rivestack\_extensions

List supported PostgreSQL extensions.

```hcl theme={null}
data "rivestack_extensions" "available" {}
```

## Import

Import existing resources into Terraform state:

```bash theme={null}
# Cluster
terraform import rivestack_cluster.example CLUSTER_ID

# Database
terraform import rivestack_cluster_database.example CLUSTER_ID/DATABASE_NAME

# User
terraform import rivestack_cluster_user.example CLUSTER_ID/USERNAME

# Extension
terraform import rivestack_cluster_extension.example CLUSTER_ID/EXTENSION/DATABASE

# Grant
terraform import rivestack_cluster_grant.example CLUSTER_ID/USERNAME/DATABASE

# Backup config
terraform import rivestack_cluster_backup_config.example CLUSTER_ID
```

## Links

* [Terraform Registry](https://registry.terraform.io/providers/Rivestack/rivestack/latest)
* [GitHub Repository](https://github.com/Rivestack/terraform-provider-rivestack)
* [Examples](https://github.com/Rivestack/terraform-provider-rivestack/tree/main/examples)
