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

# PlanetScale Terraform provider

> A resource model for Vitess and Postgres databases, designed for Terraform and OpenTofu.

Terraform is an open-source infrastructure-as-code tool that lets you define and manage cloud resources through declarative configuration files. With the [PlanetScale Terraform provider](https://github.com/planetscale/terraform-provider-planetscale), you can programmatically provision and manage your PlanetScale databases, branches, passwords, and other resources alongside the rest of your infrastructure.

## Conceptual model

The PlanetScale Terraform provider is organized around a clear distinction between **Vitess** and **Postgres** resources and is focused on long-lived infrastructure objects.

* There are separate resources for each **database kind**—Vitess or Postgres.
* The provider maps cleanly onto PlanetScale's public API while exposing Terraform-friendly fields and lifecycle behavior.

PlanetScale databases themselves (the logical database containers) are **not** managed directly as Terraform resources in v1.0. Instead:

* Create databases in PlanetScale first (via the PlanetScale UI or API).
* Use Terraform to manage **branches** and related resources (roles, passwords, etc.) within those databases.

### Credential models

**Vitess** and **Postgres** use different terminology for database credentials:

| Database Type | Resource                             | How permissions work                                                                                                                       |
| ------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
| Vitess        | `planetscale_vitess_branch_password` | Set the `role` attribute to `reader`, `writer`, `readwriter`, or `admin`                                                                   |
| Postgres      | `planetscale_postgres_branch_role`   | Use `inherited_roles` to inherit from [built-in Postgres roles](/postgres/connecting/roles) like `pg_read_all_data` or `pg_write_all_data` |

## Quick start

This complete example creates a Postgres branch with application credentials:

```hcl theme={null}
terraform {
  required_providers {
    planetscale = {
      source  = "planetscale/planetscale"
      version = "~> 1.0"
    }
  }
}

# Manage a branch (database must already exist in PlanetScale)
resource "planetscale_postgres_branch" "main" {
  organization = "my-org"
  database     = "my-db" # prefer database id over name
  name         = "main"
}

# Create application credentials
resource "planetscale_postgres_branch_role" "app" {
  organization    = "my-org"
  database        = "my-db"
  branch          = planetscale_postgres_branch.main.id
  name            = "app"
  inherited_roles = ["pg_read_all_data", "pg_write_all_data"]
}

# Output connection details
output "connection_string" {
  sensitive = true
  value     = "postgres://${planetscale_postgres_branch_role.app.username}:${planetscale_postgres_branch_role.app.password}@${planetscale_postgres_branch_role.app.access_host_url}/${planetscale_postgres_branch_role.app.database_name}"
}
```

Run:

```bash theme={null}
export PLANETSCALE_SERVICE_TOKEN_ID="your-token-id"
export PLANETSCALE_SERVICE_TOKEN="your-token"
terraform init
terraform apply
terraform output -raw connection_string
```

## Available resources

The provider offers resources for the most common automation scenarios:

* `planetscale_vitess_branch`
* `planetscale_vitess_branch_password`
* `planetscale_postgres_branch`
* `planetscale_postgres_branch_role`

## Data sources

The provider also offers data sources for reading existing resources:

* `planetscale_databases`
* `planetscale_database_postgres`
* `planetscale_database_vitess`
* `planetscale_organization`
* `planetscale_organizations`
* `planetscale_postgres_branch`
* `planetscale_postgres_branch_role`
* `planetscale_postgres_branch_roles`
* `planetscale_vitess_branch`
* `planetscale_vitess_branch_password`
* `planetscale_vitess_branch_passwords`

### Data source behavior

| Data Source                           | Required Inputs                            | Notes                                                                   |
| ------------------------------------- | ------------------------------------------ | ----------------------------------------------------------------------- |
| `planetscale_databases`               | `organization`                             | Lists all databases. Optional `q` parameter for filtering by name.      |
| `planetscale_database_postgres`       | `organization`                             | Returns Postgres database info. Does not accept a database name filter. |
| `planetscale_database_vitess`         | `organization`                             | Returns Vitess database info. Does not accept a database name filter.   |
| `planetscale_postgres_branch`         | `organization`, `database`                 | Returns the default branch. Does not accept a branch name parameter.    |
| `planetscale_postgres_branch_roles`   | `organization`, `database`, `branch`       | Lists all roles on a branch.                                            |
| `planetscale_postgres_branch_role`    | `organization`, `database`, `branch`, `id` | Fetches a specific role by ID. Useful for importing existing roles.     |
| `planetscale_vitess_branch`           | `organization`, `database`                 | Returns the default branch. Does not accept a branch name parameter.    |
| `planetscale_vitess_branch_passwords` | `organization`, `database`, `branch`       | Lists all passwords on a branch.                                        |
| `planetscale_vitess_branch_password`  | `organization`, `database`, `branch`, `id` | Fetches a specific password by ID.                                      |
| `planetscale_organization`            | `organization`                             | Returns organization details.                                           |
| `planetscale_organizations`           | (none)                                     | Lists all accessible organizations.                                     |

Refer to the [Terraform Registry and provider documentation](https://registry.terraform.io/providers/planetscale/planetscale/latest) for the full, up-to-date list of available resources and data sources.

## Provider configuration

The provider supports authentication using [service tokens](/api/reference/service-tokens).

Example configuration:

```hcl theme={null}
terraform {
  required_providers {
    planetscale = {
      source  = "planetscale/planetscale"
      version = "~> 1.0"
    }
  }
}

provider "planetscale" {
  # Credentials are read from environment variables by default:
  #   PLANETSCALE_SERVICE_TOKEN_ID
  #   PLANETSCALE_SERVICE_TOKEN
  #
  # You can also configure them explicitly (not recommended for production):
  # service_token_id = "..."
  # service_token    = "..."
}
```

| Provider Attribute | Environment Variable           | Description                  |
| ------------------ | ------------------------------ | ---------------------------- |
| `service_token_id` | `PLANETSCALE_SERVICE_TOKEN_ID` | PlanetScale Service Token ID |
| `service_token`    | `PLANETSCALE_SERVICE_TOKEN`    | PlanetScale Service Token    |
| `server_url`       | `PLANETSCALE_SERVER_URL`       | Optional server URL override |

## Example usage

### Vitess branch and password

```hcl theme={null}
resource "planetscale_vitess_branch" "app" {
  organization = "my-org"
  database     = "my-vitess-db"
  name         = "app-main"

  # Optional configuration:
  # region        = "us-east-1"   # Region for the branch
  # parent_branch = "main"        # Fork from an existing branch
  # backup_id     = "..."         # Restore from a specific backup
}

resource "planetscale_vitess_branch_password" "app_rw" {
  organization = "my-org"
  database     = "my-vitess-db"
  branch       = planetscale_vitess_branch.app.name
  name         = "app-rw"
  role         = "admin"  # Options: reader, writer, readwriter, admin

  # Optional configuration:
  # replica       = false              # Connect to read replica
  # direct_vtgate = false              # Direct VTGate connection
  # ttl           = 86400              # Credentials expire after N seconds
  # cidrs         = ["10.0.0.0/8"]     # IP allowlist
}
```

### Postgres branch and role

```hcl theme={null}
resource "planetscale_postgres_branch" "primary" {
  organization = "my-org"
  database     = "my-postgres-db"
  name         = "primary"

  # Optional configuration:
  # cluster_size  = "PS_10_AWS_ARM"
  # region        = "us-east-1"                # Region for the branch
  # parent_branch = "main"                     # Fork from an existing branch
  # major_version = "18"                       # PostgreSQL major version
  # backup_id     = "..."                      # Restore from a specific backup
  # restore_point = "2024-01-01T00:00:00Z"     # Point-in-time recovery (Postgres only)
}

resource "planetscale_postgres_branch_role" "app_role" {
  organization = "my-org"
  database     = "my-postgres-db"
  branch       = planetscale_postgres_branch.primary.id
  name         = "app_role"

  # Grant permissions by inheriting from built-in Postgres roles
  inherited_roles = [
    "pg_read_all_data",
    "pg_write_all_data",
  ]

  # Optional configuration:
  # ttl       = 86400        # Credentials expire after N seconds
  # successor = "other-role" # Role to reassign ownership to before dropping
}
```

<Warning>
  **Immutable attributes:** Changing `region`, `parent_branch`, `major_version`, `backup_id`, or `restore_point` will **destroy and recreate** the branch. Use `lifecycle { prevent_destroy = true }` to protect production branches from accidental replacement.
</Warning>

## Retrieving connection details

After creating a role or password, use Terraform outputs to retrieve connection information:

### Postgres

```hcl theme={null}
output "postgres_connection" {
  description = "Postgres connection details"
  sensitive   = true
  value = {
    host     = planetscale_postgres_branch_role.app_role.access_host_url
    username = planetscale_postgres_branch_role.app_role.username
    password = planetscale_postgres_branch_role.app_role.password
    database = planetscale_postgres_branch_role.app_role.database_name
  }
}
```

### Vitess

```hcl theme={null}
output "vitess_connection" {
  description = "Vitess connection details"
  sensitive   = true
  value = {
    host     = planetscale_vitess_branch_password.app_rw.access_host_url
    username = planetscale_vitess_branch_password.app_rw.username
    password = planetscale_vitess_branch_password.app_rw.plain_text
  }
}
```

<Note>
  The `password` (Postgres) and `plain_text` (Vitess) fields are only available after the initial `terraform apply`. They are marked as sensitive and stored in Terraform state.
</Note>

## Practical examples

### Development branch workflow

Create a development branch forked from your main branch. Optionally specify a larger cluster size if you need more resources than the default:

```hcl theme={null}
resource "planetscale_postgres_branch" "feature_auth" {
  organization  = "my-org"
  database      = "my-db"
  name          = "feature-auth"
  parent_branch = "main"
  # cluster_size = "PS_10_AWS_ARM"  # Optional: specify a larger cluster size
}
```

### Read-only role for reporting

Create a role with read-only access for analytics and reporting:

```hcl theme={null}
resource "planetscale_postgres_branch_role" "reporting" {
  organization    = "my-org"
  database        = "my-db"
  branch          = "main"
  name            = "reporting"
  inherited_roles = ["pg_read_all_data"]  # Read-only access
}
```

### Short-lived CI/CD credentials

Create credentials that automatically expire for CI/CD pipelines:

```hcl theme={null}
resource "planetscale_postgres_branch_role" "ci_runner" {
  organization    = "my-org"
  database        = "my-db"
  branch          = "main"
  name            = "ci-runner"
  inherited_roles = ["pg_read_all_data", "pg_write_all_data"]
  ttl             = 3600  # Expires in 1 hour
}
```

## Configuration reference

| Attribute                    | Valid Values                                                                                                                          |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `cluster_size`               | Use the [Clusters API](/api/reference/list_cluster_size_skus#list-available-cluster-sizes) to get the list of available cluster sizes |
| `region`                     | See [available regions](/vitess/regions)                                                                                              |
| `major_version` (Postgres)   | `17`, `18`                                                                                                                            |
| `role` (Vitess)              | `reader`, `writer`, `readwriter`, `admin`                                                                                             |
| `inherited_roles` (Postgres) | `pg_read_all_data`, `pg_write_all_data`, or any custom role                                                                           |

## Deletion protection

Branch deletion is one of the most sensitive operations in infrastructure automation. To reduce risk, use Terraform's `lifecycle` block to prevent accidental destruction of critical resources:

```hcl theme={null}
resource "planetscale_vitess_branch" "production" {
  organization = "my-org"
  database     = "my-vitess-db"
  name         = "main"

  lifecycle {
    prevent_destroy = true
  }
}
```

You should enforce your own review and approval processes around Terraform `apply`, particularly for changes that delete or recreate branches.

## Upgrading from v0.x to v1.x

The original [PlanetScale Terraform provider](https://registry.terraform.io/providers/planetscale/planetscale/0.6.1) was not officially supported for production use and is no longer maintained.

Because the new v1 provider is a **breaking rewrite**, migration from v0.x to v1.x is a one-time, manual transition. Projects using the v0 provider will continue to work as normal, but this version will not receive further updates.

1. **Pin v0.x in existing workloads**
   * Ensure all existing Terraform projects using the PlanetScale provider are pinned to `~> 0.6.1` (or a specific v0.x version) to avoid unintentional upgrades.
2. **Create a new Terraform project for v1.x**
   * Create a separate directory with a new configuration using the v1 provider.
   * Use the v1 resource types for Vitess/Postgres branches, roles, passwords, and other supported resources.
   * Run `terraform init` to download the v1 provider and initialize your working directory. This creates a new, independent state file.
3. **Import existing resources into v1.x state**
   * For each resource that you want Terraform to manage going forward, run `terraform import` for the corresponding v1 resource.
   * Expect import to use IDs that align with the v1 API design (for example, IDs rather than purely name-based identifiers).
4. **Cut over automation**
   * After resources are imported and `terraform plan` shows no unexpected changes, switch your automation (CI pipelines, etc.) to apply the v1 project.
5. **Sunset v0.x usage**
   * Once you have validated v1.x in production, retire the v0.x configurations and keep them only for historical reference, if needed.

## Importing existing resources

Resources are imported using JSON-encoded identifiers:

```bash theme={null}
# Import a Postgres branch
terraform import planetscale_postgres_branch.main \
  '{"organization": "my-org", "database": "my-db", "id": "branch-id"}'

# Import a Postgres branch role
terraform import planetscale_postgres_branch_role.app \
  '{"organization": "my-org", "database": "my-db", "branch": "main", "id": "role-id"}'

# Import a Vitess branch
terraform import planetscale_vitess_branch.main \
  '{"organization": "my-org", "database": "my-db", "id": "branch-id"}'

# Import a Vitess branch password
terraform import planetscale_vitess_branch_password.app \
  '{"organization": "my-org", "database": "my-db", "branch": "main", "id": "password-id"}'
```

You can find resource IDs in the PlanetScale dashboard URL or via the API.

## Need help?

Get help from [the PlanetScale Support team](https://planetscale.com/contact?initial=support), or join our [Discord community](https://pscale.link/community) to see how others are using PlanetScale.
